@hazbase/simplicity 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -0
- package/dist/cli.js +91 -1
- package/dist/client/ContractFactory.d.ts +2 -1
- package/dist/client/ContractFactory.js +3 -0
- package/dist/client/DeployedContract.d.ts +15 -1
- package/dist/client/DeployedContract.js +22 -0
- package/dist/client/SimplicityClient.d.ts +39 -1
- package/dist/client/SimplicityClient.js +29 -0
- package/dist/core/artifact.js +8 -0
- package/dist/core/compiler.js +60 -5
- package/dist/core/executor.js +24 -0
- package/dist/core/state.d.ts +18 -0
- package/dist/core/state.js +278 -0
- package/dist/core/types.d.ts +73 -0
- package/dist/domain/bond.d.ts +59 -0
- package/dist/domain/bond.js +128 -0
- package/dist/domain/bondValidation.d.ts +9 -0
- package/dist/domain/bondValidation.js +90 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -1
- package/package.json +1 -1
package/dist/core/executor.js
CHANGED
|
@@ -213,6 +213,13 @@ function buildPsetSummary(decoded, meta) {
|
|
|
213
213
|
trustMode: meta.definitionTrustMode ?? null,
|
|
214
214
|
anchorMode: meta.definitionAnchorMode ?? null,
|
|
215
215
|
},
|
|
216
|
+
state: {
|
|
217
|
+
type: meta.stateType ?? null,
|
|
218
|
+
id: meta.stateId ?? null,
|
|
219
|
+
hash: meta.stateHash ?? null,
|
|
220
|
+
trustMode: meta.stateTrustMode ?? null,
|
|
221
|
+
anchorMode: meta.stateAnchorMode ?? null,
|
|
222
|
+
},
|
|
216
223
|
contract: {
|
|
217
224
|
address: meta.contractAddress,
|
|
218
225
|
cmr: meta.cmr,
|
|
@@ -304,6 +311,11 @@ async function buildExecutionState(config, artifact, input) {
|
|
|
304
311
|
definitionHash: artifact.definition?.hash,
|
|
305
312
|
definitionTrustMode: artifact.definition?.trustMode,
|
|
306
313
|
definitionAnchorMode: artifact.definition?.anchorMode,
|
|
314
|
+
stateType: artifact.state?.stateType,
|
|
315
|
+
stateId: artifact.state?.stateId,
|
|
316
|
+
stateHash: artifact.state?.hash,
|
|
317
|
+
stateTrustMode: artifact.state?.trustMode,
|
|
318
|
+
stateAnchorMode: artifact.state?.anchorMode,
|
|
307
319
|
expectedLiquidReceiver: input.expectedLiquidReceiver ?? recipientAddress,
|
|
308
320
|
contractAddress: artifact.compiled.contractAddress,
|
|
309
321
|
cmr: artifact.compiled.cmr,
|
|
@@ -460,6 +472,11 @@ async function executeGaslessContractCall(config, artifact, input) {
|
|
|
460
472
|
definitionHash: artifact.definition?.hash,
|
|
461
473
|
definitionTrustMode: artifact.definition?.trustMode,
|
|
462
474
|
definitionAnchorMode: artifact.definition?.anchorMode,
|
|
475
|
+
stateType: artifact.state?.stateType,
|
|
476
|
+
stateId: artifact.state?.stateId,
|
|
477
|
+
stateHash: artifact.state?.hash,
|
|
478
|
+
stateTrustMode: artifact.state?.trustMode,
|
|
479
|
+
stateAnchorMode: artifact.state?.anchorMode,
|
|
463
480
|
contractAddress: artifact.compiled.contractAddress,
|
|
464
481
|
cmr: artifact.compiled.cmr,
|
|
465
482
|
internalKey: artifact.compiled.internalKey,
|
|
@@ -653,6 +670,13 @@ async function executeRelayedGaslessContractCall(config, artifact, input, relaye
|
|
|
653
670
|
trustMode: artifact.definition?.trustMode ?? null,
|
|
654
671
|
anchorMode: artifact.definition?.anchorMode ?? null,
|
|
655
672
|
},
|
|
673
|
+
state: {
|
|
674
|
+
type: artifact.state?.stateType ?? null,
|
|
675
|
+
id: artifact.state?.stateId ?? null,
|
|
676
|
+
hash: artifact.state?.hash ?? null,
|
|
677
|
+
trustMode: artifact.state?.trustMode ?? null,
|
|
678
|
+
anchorMode: artifact.state?.anchorMode ?? null,
|
|
679
|
+
},
|
|
656
680
|
contract: {
|
|
657
681
|
address: request.detailedSummary.contract.contractAddress,
|
|
658
682
|
cmr: request.detailedSummary.contract.cmr,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ArtifactStateMetadata, DefinitionAnchorMode, SimplicityArtifact, StateDocumentDescriptor, StateDocumentInput, StateVerificationResult } from "./types";
|
|
2
|
+
export declare function loadStateInput(input: StateDocumentInput): Promise<StateDocumentDescriptor>;
|
|
3
|
+
export declare function detectOnChainStateAnchor(simfSource: string): {
|
|
4
|
+
sourceVerified: boolean;
|
|
5
|
+
helper?: "nonzero-eq_256";
|
|
6
|
+
reason?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function buildArtifactStateMetadata(state: StateDocumentDescriptor, options?: {
|
|
9
|
+
anchorMode?: DefinitionAnchorMode;
|
|
10
|
+
onChainAnchor?: ArtifactStateMetadata["onChainAnchor"];
|
|
11
|
+
}): ArtifactStateMetadata;
|
|
12
|
+
export declare function verifyStateDescriptorAgainstArtifact(state: StateDocumentDescriptor, artifactState?: ArtifactStateMetadata, expectedType?: string, expectedId?: string): StateVerificationResult;
|
|
13
|
+
export declare function verifyStateAgainstArtifact(input: {
|
|
14
|
+
artifact: SimplicityArtifact;
|
|
15
|
+
state: StateDocumentInput;
|
|
16
|
+
expectedType?: string;
|
|
17
|
+
expectedId?: string;
|
|
18
|
+
}): Promise<StateVerificationResult>;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadStateInput = loadStateInput;
|
|
7
|
+
exports.detectOnChainStateAnchor = detectOnChainStateAnchor;
|
|
8
|
+
exports.buildArtifactStateMetadata = buildArtifactStateMetadata;
|
|
9
|
+
exports.verifyStateDescriptorAgainstArtifact = verifyStateDescriptorAgainstArtifact;
|
|
10
|
+
exports.verifyStateAgainstArtifact = verifyStateAgainstArtifact;
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
12
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const errors_1 = require("./errors");
|
|
14
|
+
const summary_1 = require("./summary");
|
|
15
|
+
const DEFAULT_SCHEMA_VERSION = "1";
|
|
16
|
+
const DEFAULT_ANCHOR_MODE = "artifact-hash-anchor";
|
|
17
|
+
const ZERO_HASH_256 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
18
|
+
function stripComments(source) {
|
|
19
|
+
return source
|
|
20
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
21
|
+
.replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
22
|
+
}
|
|
23
|
+
function extractFunctionBody(source, functionName) {
|
|
24
|
+
const marker = `fn ${functionName}()`;
|
|
25
|
+
const start = source.indexOf(marker);
|
|
26
|
+
if (start === -1)
|
|
27
|
+
return null;
|
|
28
|
+
const braceStart = source.indexOf("{", start);
|
|
29
|
+
if (braceStart === -1)
|
|
30
|
+
return null;
|
|
31
|
+
let depth = 0;
|
|
32
|
+
for (let i = braceStart; i < source.length; i += 1) {
|
|
33
|
+
const char = source[i];
|
|
34
|
+
if (char === "{")
|
|
35
|
+
depth += 1;
|
|
36
|
+
if (char === "}") {
|
|
37
|
+
depth -= 1;
|
|
38
|
+
if (depth === 0) {
|
|
39
|
+
return source.slice(braceStart + 1, i);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function assertNonEmpty(value, fieldName) {
|
|
46
|
+
if (!value || value.trim().length === 0) {
|
|
47
|
+
throw new errors_1.DefinitionError(`${fieldName} must not be empty`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function ensureSerializable(value, seen = new WeakSet()) {
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
throw new errors_1.DefinitionError("State JSON must not contain undefined values");
|
|
54
|
+
}
|
|
55
|
+
if (value === null)
|
|
56
|
+
return;
|
|
57
|
+
if (typeof value === "bigint") {
|
|
58
|
+
throw new errors_1.DefinitionError("State JSON must not contain bigint values");
|
|
59
|
+
}
|
|
60
|
+
if (value instanceof Date) {
|
|
61
|
+
throw new errors_1.DefinitionError("State JSON must not contain Date objects; normalize them first");
|
|
62
|
+
}
|
|
63
|
+
if (Array.isArray(value)) {
|
|
64
|
+
for (const entry of value)
|
|
65
|
+
ensureSerializable(entry, seen);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (typeof value === "object") {
|
|
69
|
+
const objectValue = value;
|
|
70
|
+
if (seen.has(objectValue)) {
|
|
71
|
+
throw new errors_1.DefinitionError("State JSON must not contain circular references");
|
|
72
|
+
}
|
|
73
|
+
seen.add(objectValue);
|
|
74
|
+
for (const entry of Object.values(objectValue))
|
|
75
|
+
ensureSerializable(entry, seen);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function resolveStateValue(input) {
|
|
79
|
+
if ((input.jsonPath ? 1 : 0) + (input.value !== undefined ? 1 : 0) !== 1) {
|
|
80
|
+
throw new errors_1.DefinitionError("Exactly one of jsonPath or value must be provided");
|
|
81
|
+
}
|
|
82
|
+
if (input.jsonPath) {
|
|
83
|
+
const sourcePath = node_path_1.default.resolve(input.jsonPath);
|
|
84
|
+
const raw = await (0, promises_1.readFile)(sourcePath, "utf8");
|
|
85
|
+
try {
|
|
86
|
+
return { value: JSON.parse(raw), sourcePath };
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new errors_1.DefinitionError(`Failed to parse state JSON at ${sourcePath}`, error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { value: input.value };
|
|
93
|
+
}
|
|
94
|
+
async function loadStateInput(input) {
|
|
95
|
+
const stateType = assertNonEmpty(input.type, "state.type");
|
|
96
|
+
const stateId = assertNonEmpty(input.id, "state.id");
|
|
97
|
+
const schemaVersion = assertNonEmpty(input.schemaVersion ?? DEFAULT_SCHEMA_VERSION, "state.schemaVersion");
|
|
98
|
+
const { value, sourcePath } = await resolveStateValue(input);
|
|
99
|
+
ensureSerializable(value);
|
|
100
|
+
const canonicalJson = (0, summary_1.stableStringify)(value);
|
|
101
|
+
return {
|
|
102
|
+
stateType,
|
|
103
|
+
stateId,
|
|
104
|
+
schemaVersion,
|
|
105
|
+
canonicalJson,
|
|
106
|
+
hash: (0, summary_1.sha256HexUtf8)(canonicalJson),
|
|
107
|
+
sourcePath,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function detectOnChainStateAnchor(simfSource) {
|
|
111
|
+
const source = stripComments(simfSource.replace(/\r\n/g, "\n"));
|
|
112
|
+
if (!source.includes("{{STATE_HASH}}")) {
|
|
113
|
+
return { sourceVerified: false, reason: "STATE_HASH placeholder is missing" };
|
|
114
|
+
}
|
|
115
|
+
const helperBody = extractFunctionBody(source, "require_state_anchor");
|
|
116
|
+
if (!helperBody) {
|
|
117
|
+
return { sourceVerified: false, reason: "Required state anchor helper function is missing" };
|
|
118
|
+
}
|
|
119
|
+
if (!helperBody.includes("let anchored_state_hash: u256 = 0x{{STATE_HASH}};")) {
|
|
120
|
+
return { sourceVerified: false, reason: "Required anchored_state_hash assignment is missing" };
|
|
121
|
+
}
|
|
122
|
+
if (!helperBody.includes(`let zero_hash: u256 = ${ZERO_HASH_256};`)) {
|
|
123
|
+
return { sourceVerified: false, reason: "Required zero_hash assignment is missing" };
|
|
124
|
+
}
|
|
125
|
+
if (!helperBody.includes("assert!(not(jet::eq_256(anchored_state_hash, zero_hash)));")) {
|
|
126
|
+
return { sourceVerified: false, reason: "Required eq_256 assertion is missing" };
|
|
127
|
+
}
|
|
128
|
+
const mainBody = extractFunctionBody(source, "main");
|
|
129
|
+
if (!mainBody) {
|
|
130
|
+
return { sourceVerified: false, reason: "main function is missing" };
|
|
131
|
+
}
|
|
132
|
+
if (!mainBody.includes("require_state_anchor();")) {
|
|
133
|
+
return { sourceVerified: false, reason: "require_state_anchor() is not called from main" };
|
|
134
|
+
}
|
|
135
|
+
return { sourceVerified: true, helper: "nonzero-eq_256" };
|
|
136
|
+
}
|
|
137
|
+
function buildArtifactStateMetadata(state, options) {
|
|
138
|
+
return {
|
|
139
|
+
stateType: state.stateType,
|
|
140
|
+
stateId: state.stateId,
|
|
141
|
+
schemaVersion: state.schemaVersion,
|
|
142
|
+
hash: state.hash,
|
|
143
|
+
trustMode: "hash-anchor",
|
|
144
|
+
anchorMode: options?.anchorMode ?? DEFAULT_ANCHOR_MODE,
|
|
145
|
+
onChainAnchor: options?.onChainAnchor,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function verifyStateDescriptorAgainstArtifact(state, artifactState, expectedType, expectedId) {
|
|
149
|
+
const noStateTrust = {
|
|
150
|
+
artifactMatch: false,
|
|
151
|
+
onChainAnchorPresent: false,
|
|
152
|
+
onChainAnchorVerified: false,
|
|
153
|
+
effectiveMode: "none",
|
|
154
|
+
};
|
|
155
|
+
if (expectedType && expectedType !== state.stateType) {
|
|
156
|
+
return {
|
|
157
|
+
ok: false,
|
|
158
|
+
reason: `State type mismatch: expected=${expectedType} actual=${state.stateType}`,
|
|
159
|
+
state,
|
|
160
|
+
artifactState,
|
|
161
|
+
trust: noStateTrust,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (expectedId && expectedId !== state.stateId) {
|
|
165
|
+
return {
|
|
166
|
+
ok: false,
|
|
167
|
+
reason: `State id mismatch: expected=${expectedId} actual=${state.stateId}`,
|
|
168
|
+
state,
|
|
169
|
+
artifactState,
|
|
170
|
+
trust: noStateTrust,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (!artifactState) {
|
|
174
|
+
return {
|
|
175
|
+
ok: false,
|
|
176
|
+
reason: "Artifact does not contain state metadata",
|
|
177
|
+
state,
|
|
178
|
+
trust: noStateTrust,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const trust = {
|
|
182
|
+
artifactMatch: false,
|
|
183
|
+
onChainAnchorPresent: artifactState.anchorMode === "on-chain-constant-committed",
|
|
184
|
+
onChainAnchorVerified: false,
|
|
185
|
+
effectiveMode: artifactState.anchorMode,
|
|
186
|
+
};
|
|
187
|
+
if (artifactState.stateType !== state.stateType) {
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
reason: `State type mismatch: artifact=${artifactState.stateType} actual=${state.stateType}`,
|
|
191
|
+
state,
|
|
192
|
+
artifactState,
|
|
193
|
+
trust,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (artifactState.stateId !== state.stateId) {
|
|
197
|
+
return {
|
|
198
|
+
ok: false,
|
|
199
|
+
reason: `State id mismatch: artifact=${artifactState.stateId} actual=${state.stateId}`,
|
|
200
|
+
state,
|
|
201
|
+
artifactState,
|
|
202
|
+
trust,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (artifactState.schemaVersion !== state.schemaVersion) {
|
|
206
|
+
return {
|
|
207
|
+
ok: false,
|
|
208
|
+
reason: `State schemaVersion mismatch: artifact=${artifactState.schemaVersion} actual=${state.schemaVersion}`,
|
|
209
|
+
state,
|
|
210
|
+
artifactState,
|
|
211
|
+
trust,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (artifactState.hash !== state.hash) {
|
|
215
|
+
return {
|
|
216
|
+
ok: false,
|
|
217
|
+
reason: `State hash mismatch: artifact=${artifactState.hash} actual=${state.hash}`,
|
|
218
|
+
state,
|
|
219
|
+
artifactState,
|
|
220
|
+
trust,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
ok: true,
|
|
225
|
+
state,
|
|
226
|
+
artifactState,
|
|
227
|
+
trust: {
|
|
228
|
+
...trust,
|
|
229
|
+
artifactMatch: true,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async function resolveStateTrust(artifact, baseTrust) {
|
|
234
|
+
if (!artifact.state) {
|
|
235
|
+
return {
|
|
236
|
+
artifactMatch: false,
|
|
237
|
+
onChainAnchorPresent: false,
|
|
238
|
+
onChainAnchorVerified: false,
|
|
239
|
+
effectiveMode: "none",
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (artifact.state.anchorMode !== "on-chain-constant-committed") {
|
|
243
|
+
return baseTrust;
|
|
244
|
+
}
|
|
245
|
+
const sourcePath = artifact.source.mode === "file" ? artifact.source.simfPath : undefined;
|
|
246
|
+
if (!sourcePath) {
|
|
247
|
+
return {
|
|
248
|
+
...baseTrust,
|
|
249
|
+
onChainAnchorPresent: true,
|
|
250
|
+
onChainAnchorVerified: false,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const source = await (0, promises_1.readFile)(sourcePath, "utf8");
|
|
255
|
+
const detection = detectOnChainStateAnchor(source);
|
|
256
|
+
return {
|
|
257
|
+
...baseTrust,
|
|
258
|
+
onChainAnchorPresent: true,
|
|
259
|
+
onChainAnchorVerified: detection.sourceVerified,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return {
|
|
264
|
+
...baseTrust,
|
|
265
|
+
onChainAnchorPresent: true,
|
|
266
|
+
onChainAnchorVerified: false,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async function verifyStateAgainstArtifact(input) {
|
|
271
|
+
const state = await loadStateInput(input.state);
|
|
272
|
+
const base = verifyStateDescriptorAgainstArtifact(state, input.artifact.state, input.expectedType, input.expectedId);
|
|
273
|
+
const trust = await resolveStateTrust(input.artifact, base.trust);
|
|
274
|
+
return {
|
|
275
|
+
...base,
|
|
276
|
+
trust,
|
|
277
|
+
};
|
|
278
|
+
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -71,6 +71,7 @@ export interface SimplicityArtifact {
|
|
|
71
71
|
notes: string | null;
|
|
72
72
|
};
|
|
73
73
|
definition?: ArtifactDefinitionMetadata;
|
|
74
|
+
state?: ArtifactStateMetadata;
|
|
74
75
|
legacy?: {
|
|
75
76
|
simfTemplatePath?: string;
|
|
76
77
|
params?: {
|
|
@@ -85,12 +86,14 @@ export interface CompileFromFileInput {
|
|
|
85
86
|
templateVars?: Record<string, string | number>;
|
|
86
87
|
artifactPath?: string;
|
|
87
88
|
definition?: DefinitionInput;
|
|
89
|
+
state?: StateDocumentInput;
|
|
88
90
|
}
|
|
89
91
|
export interface CompileFromPresetInput {
|
|
90
92
|
preset: string;
|
|
91
93
|
params: Record<string, string | number>;
|
|
92
94
|
artifactPath?: string;
|
|
93
95
|
definition?: DefinitionInput;
|
|
96
|
+
state?: StateDocumentInput;
|
|
94
97
|
}
|
|
95
98
|
export interface DefinitionInput {
|
|
96
99
|
type: string;
|
|
@@ -108,6 +111,22 @@ export interface DefinitionDescriptor {
|
|
|
108
111
|
hash: string;
|
|
109
112
|
sourcePath?: string;
|
|
110
113
|
}
|
|
114
|
+
export interface StateDocumentInput {
|
|
115
|
+
type: string;
|
|
116
|
+
id: string;
|
|
117
|
+
schemaVersion?: string;
|
|
118
|
+
jsonPath?: string;
|
|
119
|
+
value?: unknown;
|
|
120
|
+
anchorMode?: DefinitionAnchorMode;
|
|
121
|
+
}
|
|
122
|
+
export interface StateDocumentDescriptor {
|
|
123
|
+
stateType: string;
|
|
124
|
+
stateId: string;
|
|
125
|
+
schemaVersion: string;
|
|
126
|
+
canonicalJson: string;
|
|
127
|
+
hash: string;
|
|
128
|
+
sourcePath?: string;
|
|
129
|
+
}
|
|
111
130
|
export interface ArtifactDefinitionMetadata {
|
|
112
131
|
definitionType: string;
|
|
113
132
|
definitionId: string;
|
|
@@ -121,6 +140,19 @@ export interface ArtifactDefinitionMetadata {
|
|
|
121
140
|
sourceVerified: boolean;
|
|
122
141
|
};
|
|
123
142
|
}
|
|
143
|
+
export interface ArtifactStateMetadata {
|
|
144
|
+
stateType: string;
|
|
145
|
+
stateId: string;
|
|
146
|
+
schemaVersion: string;
|
|
147
|
+
hash: string;
|
|
148
|
+
trustMode: DefinitionTrustMode;
|
|
149
|
+
anchorMode: DefinitionAnchorMode;
|
|
150
|
+
onChainAnchor?: {
|
|
151
|
+
helper: "nonzero-eq_256";
|
|
152
|
+
templateVar: "STATE_HASH";
|
|
153
|
+
sourceVerified: boolean;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
124
156
|
export interface DeploymentInfo {
|
|
125
157
|
contractAddress: string;
|
|
126
158
|
internalKey: string;
|
|
@@ -192,6 +224,13 @@ export interface PsetSummary {
|
|
|
192
224
|
trustMode: DefinitionTrustMode | null;
|
|
193
225
|
anchorMode: DefinitionAnchorMode | null;
|
|
194
226
|
};
|
|
227
|
+
state?: {
|
|
228
|
+
type: string | null;
|
|
229
|
+
id: string | null;
|
|
230
|
+
hash: string | null;
|
|
231
|
+
trustMode: DefinitionTrustMode | null;
|
|
232
|
+
anchorMode: DefinitionAnchorMode | null;
|
|
233
|
+
};
|
|
195
234
|
contract: {
|
|
196
235
|
address: string;
|
|
197
236
|
cmr: string;
|
|
@@ -271,6 +310,40 @@ export interface DefinitionVerificationResult {
|
|
|
271
310
|
effectiveMode: "none" | DefinitionAnchorMode;
|
|
272
311
|
};
|
|
273
312
|
}
|
|
313
|
+
export interface StateVerificationResult {
|
|
314
|
+
ok: boolean;
|
|
315
|
+
reason?: string;
|
|
316
|
+
state: StateDocumentDescriptor;
|
|
317
|
+
artifactState?: ArtifactStateMetadata;
|
|
318
|
+
trust: {
|
|
319
|
+
artifactMatch: boolean;
|
|
320
|
+
onChainAnchorPresent: boolean;
|
|
321
|
+
onChainAnchorVerified: boolean;
|
|
322
|
+
effectiveMode: "none" | DefinitionAnchorMode;
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
export interface BondDefinition {
|
|
326
|
+
bondId: string;
|
|
327
|
+
issuer: string;
|
|
328
|
+
faceValue: number;
|
|
329
|
+
couponBps: number;
|
|
330
|
+
issueDate: string;
|
|
331
|
+
maturityDate: number;
|
|
332
|
+
currencyAssetId: string;
|
|
333
|
+
controllerXonly: string;
|
|
334
|
+
}
|
|
335
|
+
export interface BondIssuanceState {
|
|
336
|
+
issuanceId: string;
|
|
337
|
+
bondId: string;
|
|
338
|
+
issuerEntityId: string;
|
|
339
|
+
issuedPrincipal: number;
|
|
340
|
+
outstandingPrincipal: number;
|
|
341
|
+
redeemedPrincipal: number;
|
|
342
|
+
currencyAssetId: string;
|
|
343
|
+
controllerXonly: string;
|
|
344
|
+
issuedAt: string;
|
|
345
|
+
status: "ISSUED" | "REDEEMED";
|
|
346
|
+
}
|
|
274
347
|
export interface WaitForFundingInput {
|
|
275
348
|
minAmountSat?: number;
|
|
276
349
|
pollIntervalMs?: number;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { SimplicityClient } from "../client/SimplicityClient";
|
|
2
|
+
import { BondDefinition, BondIssuanceState, SimplicityArtifact } from "../core/types";
|
|
3
|
+
export declare function defineBond(sdk: SimplicityClient, input: {
|
|
4
|
+
definitionPath?: string;
|
|
5
|
+
definitionValue?: BondDefinition;
|
|
6
|
+
issuancePath?: string;
|
|
7
|
+
issuanceValue?: BondIssuanceState;
|
|
8
|
+
simfPath?: string;
|
|
9
|
+
artifactPath?: string;
|
|
10
|
+
}): Promise<import("..").CompiledContract>;
|
|
11
|
+
export declare function verifyBond(sdk: SimplicityClient, input: {
|
|
12
|
+
artifactPath?: string;
|
|
13
|
+
artifact?: SimplicityArtifact;
|
|
14
|
+
definitionPath?: string;
|
|
15
|
+
definitionValue?: BondDefinition;
|
|
16
|
+
issuancePath?: string;
|
|
17
|
+
issuanceValue?: BondIssuanceState;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
artifact: SimplicityArtifact;
|
|
20
|
+
definition: import("../core/types").DefinitionVerificationResult;
|
|
21
|
+
issuance: import("../core/types").StateVerificationResult;
|
|
22
|
+
crossChecks: {
|
|
23
|
+
bondIdMatch: boolean;
|
|
24
|
+
currencyMatch: boolean;
|
|
25
|
+
controllerMatch: boolean;
|
|
26
|
+
principalInvariantValid: boolean;
|
|
27
|
+
};
|
|
28
|
+
}>;
|
|
29
|
+
export declare function loadBond(sdk: SimplicityClient, input: {
|
|
30
|
+
artifactPath: string;
|
|
31
|
+
definitionPath?: string;
|
|
32
|
+
definitionValue?: BondDefinition;
|
|
33
|
+
issuancePath?: string;
|
|
34
|
+
issuanceValue?: BondIssuanceState;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
artifact: SimplicityArtifact;
|
|
37
|
+
definition: import("../core/types").DefinitionVerificationResult;
|
|
38
|
+
issuance: import("../core/types").StateVerificationResult;
|
|
39
|
+
crossChecks: {
|
|
40
|
+
bondIdMatch: boolean;
|
|
41
|
+
currencyMatch: boolean;
|
|
42
|
+
controllerMatch: boolean;
|
|
43
|
+
principalInvariantValid: boolean;
|
|
44
|
+
};
|
|
45
|
+
trust: {
|
|
46
|
+
definitionTrust: {
|
|
47
|
+
artifactMatch: boolean;
|
|
48
|
+
onChainAnchorPresent: boolean;
|
|
49
|
+
onChainAnchorVerified: boolean;
|
|
50
|
+
effectiveMode: "none" | import("../core/types").DefinitionAnchorMode;
|
|
51
|
+
};
|
|
52
|
+
issuanceTrust: {
|
|
53
|
+
artifactMatch: boolean;
|
|
54
|
+
onChainAnchorPresent: boolean;
|
|
55
|
+
onChainAnchorVerified: boolean;
|
|
56
|
+
effectiveMode: "none" | import("../core/types").DefinitionAnchorMode;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
}>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.defineBond = defineBond;
|
|
7
|
+
exports.verifyBond = verifyBond;
|
|
8
|
+
exports.loadBond = loadBond;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const bondValidation_1 = require("./bondValidation");
|
|
11
|
+
function resolveValueOrPath(options) {
|
|
12
|
+
if (options.pathValue)
|
|
13
|
+
return { jsonPath: options.pathValue };
|
|
14
|
+
if (options.objectValue !== undefined)
|
|
15
|
+
return { value: options.objectValue };
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
async function defineBond(sdk, input) {
|
|
19
|
+
const definitionSource = resolveValueOrPath({
|
|
20
|
+
pathValue: input.definitionPath,
|
|
21
|
+
objectValue: input.definitionValue,
|
|
22
|
+
});
|
|
23
|
+
const issuanceSource = resolveValueOrPath({
|
|
24
|
+
pathValue: input.issuancePath,
|
|
25
|
+
objectValue: input.issuanceValue,
|
|
26
|
+
});
|
|
27
|
+
const initialDefinitionDescriptor = await sdk.loadDefinition({
|
|
28
|
+
type: "bond",
|
|
29
|
+
id: input.definitionValue?.bondId ?? "BOND-2026-001",
|
|
30
|
+
...definitionSource,
|
|
31
|
+
});
|
|
32
|
+
const definition = (0, bondValidation_1.validateBondDefinition)(JSON.parse(initialDefinitionDescriptor.canonicalJson));
|
|
33
|
+
const definitionDescriptor = await sdk.loadDefinition({
|
|
34
|
+
type: "bond",
|
|
35
|
+
id: definition.bondId,
|
|
36
|
+
...(definitionSource.jsonPath ? { jsonPath: definitionSource.jsonPath } : { value: definition }),
|
|
37
|
+
});
|
|
38
|
+
const initialStateDescriptor = await sdk.loadStateDocument({
|
|
39
|
+
type: "bond-issuance",
|
|
40
|
+
id: input.issuanceValue?.issuanceId ?? "BOND-2026-001-ISSUE-1",
|
|
41
|
+
...issuanceSource,
|
|
42
|
+
});
|
|
43
|
+
const issuance = (0, bondValidation_1.validateBondIssuanceState)(JSON.parse(initialStateDescriptor.canonicalJson));
|
|
44
|
+
const stateDescriptor = await sdk.loadStateDocument({
|
|
45
|
+
type: "bond-issuance",
|
|
46
|
+
id: issuance.issuanceId,
|
|
47
|
+
...(issuanceSource.jsonPath ? { jsonPath: issuanceSource.jsonPath } : { value: issuance }),
|
|
48
|
+
});
|
|
49
|
+
(0, bondValidation_1.validateBondCrossChecks)(definition, issuance);
|
|
50
|
+
const simfPath = input.simfPath ?? node_path_1.default.resolve(process.cwd(), "docs/definitions/bond-issuance-anchor.simf");
|
|
51
|
+
return sdk.compileFromFile({
|
|
52
|
+
simfPath,
|
|
53
|
+
templateVars: {
|
|
54
|
+
MIN_HEIGHT: definition.maturityDate,
|
|
55
|
+
SIGNER_XONLY: definition.controllerXonly,
|
|
56
|
+
},
|
|
57
|
+
definition: {
|
|
58
|
+
type: definitionDescriptor.definitionType,
|
|
59
|
+
id: definitionDescriptor.definitionId,
|
|
60
|
+
schemaVersion: definitionDescriptor.schemaVersion,
|
|
61
|
+
...(definitionDescriptor.sourcePath ? { jsonPath: definitionDescriptor.sourcePath } : { value: definition }),
|
|
62
|
+
anchorMode: "on-chain-constant-committed",
|
|
63
|
+
},
|
|
64
|
+
state: {
|
|
65
|
+
type: stateDescriptor.stateType,
|
|
66
|
+
id: stateDescriptor.stateId,
|
|
67
|
+
schemaVersion: stateDescriptor.schemaVersion,
|
|
68
|
+
...(stateDescriptor.sourcePath ? { jsonPath: stateDescriptor.sourcePath } : { value: issuance }),
|
|
69
|
+
anchorMode: "on-chain-constant-committed",
|
|
70
|
+
},
|
|
71
|
+
artifactPath: input.artifactPath,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async function verifyBond(sdk, input) {
|
|
75
|
+
const artifact = input.artifact ?? (input.artifactPath ? (await sdk.loadArtifact(input.artifactPath)).artifact : undefined);
|
|
76
|
+
if (!artifact) {
|
|
77
|
+
throw new Error("artifactPath or artifact is required");
|
|
78
|
+
}
|
|
79
|
+
const definitionSource = resolveValueOrPath({
|
|
80
|
+
pathValue: input.definitionPath,
|
|
81
|
+
objectValue: input.definitionValue,
|
|
82
|
+
});
|
|
83
|
+
const issuanceSource = resolveValueOrPath({
|
|
84
|
+
pathValue: input.issuancePath,
|
|
85
|
+
objectValue: input.issuanceValue,
|
|
86
|
+
});
|
|
87
|
+
const definition = await sdk.verifyDefinitionAgainstArtifact({
|
|
88
|
+
artifact,
|
|
89
|
+
type: "bond",
|
|
90
|
+
id: artifact.definition?.definitionId,
|
|
91
|
+
...definitionSource,
|
|
92
|
+
});
|
|
93
|
+
const issuance = await sdk.verifyStateAgainstArtifact({
|
|
94
|
+
artifact,
|
|
95
|
+
type: "bond-issuance",
|
|
96
|
+
id: artifact.state?.stateId,
|
|
97
|
+
...issuanceSource,
|
|
98
|
+
});
|
|
99
|
+
const definitionValue = (0, bondValidation_1.validateBondDefinition)(JSON.parse(definition.definition.canonicalJson));
|
|
100
|
+
const issuanceValue = (0, bondValidation_1.validateBondIssuanceState)(JSON.parse(issuance.state.canonicalJson));
|
|
101
|
+
const crossChecks = (0, bondValidation_1.validateBondCrossChecks)(definitionValue, issuanceValue);
|
|
102
|
+
return {
|
|
103
|
+
artifact,
|
|
104
|
+
definition,
|
|
105
|
+
issuance,
|
|
106
|
+
crossChecks,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function loadBond(sdk, input) {
|
|
110
|
+
const compiled = await sdk.loadArtifact(input.artifactPath);
|
|
111
|
+
const verification = await verifyBond(sdk, {
|
|
112
|
+
artifact: compiled.artifact,
|
|
113
|
+
definitionPath: input.definitionPath,
|
|
114
|
+
definitionValue: input.definitionValue,
|
|
115
|
+
issuancePath: input.issuancePath,
|
|
116
|
+
issuanceValue: input.issuanceValue,
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
artifact: compiled.artifact,
|
|
120
|
+
definition: verification.definition,
|
|
121
|
+
issuance: verification.issuance,
|
|
122
|
+
crossChecks: verification.crossChecks,
|
|
123
|
+
trust: {
|
|
124
|
+
definitionTrust: verification.definition.trust,
|
|
125
|
+
issuanceTrust: verification.issuance.trust,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BondDefinition, BondIssuanceState } from "../core/types";
|
|
2
|
+
export declare function validateBondDefinition(value: unknown): BondDefinition;
|
|
3
|
+
export declare function validateBondIssuanceState(value: unknown): BondIssuanceState;
|
|
4
|
+
export declare function validateBondCrossChecks(definition: BondDefinition, issuance: BondIssuanceState): {
|
|
5
|
+
bondIdMatch: boolean;
|
|
6
|
+
currencyMatch: boolean;
|
|
7
|
+
controllerMatch: boolean;
|
|
8
|
+
principalInvariantValid: boolean;
|
|
9
|
+
};
|