@hazbase/simplicity 0.0.2 → 0.0.3
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 +12 -0
- package/dist/cli.js +11 -2
- package/dist/client/DeployedContract.d.ts +1 -0
- package/dist/client/DeployedContract.js +1 -0
- package/dist/core/artifact.js +10 -1
- package/dist/core/compiler.js +52 -3
- package/dist/core/definition.d.ts +10 -2
- package/dist/core/definition.js +132 -3
- package/dist/core/executor.js +4 -0
- package/dist/core/types.d.ts +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# @hazbase/simplicity
|
|
2
|
+
[](https://badge.fury.io/js/@hazbase%2Fsimplicity)
|
|
3
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
2
4
|
|
|
3
5
|
`@hazbase/simplicity` is a Node.js / TypeScript SDK for working with Simplicity contracts on Liquid with an EVM-like developer workflow. It lets you compile SimplicityHL (`.simf`) contracts, derive the contract address, fund that address, inspect the spend you are about to make, execute the contract, and optionally run fee-sponsored flows through a sponsor wallet or relayer. It also ships with built-in presets so you can start from known-good contract templates before moving to custom `.simf` code.
|
|
4
6
|
|
|
@@ -72,6 +74,13 @@ What that means:
|
|
|
72
74
|
- injects `DEFINITION_HASH` and `DEFINITION_ID` into compile-time template vars when a definition is provided,
|
|
73
75
|
- lets you verify later that the JSON you are reading still matches the contract/artifact it was compiled against.
|
|
74
76
|
|
|
77
|
+
There are now two anchor modes:
|
|
78
|
+
- `artifact-hash-anchor`: the JSON hash is anchored in the artifact and verified later against that artifact.
|
|
79
|
+
- `on-chain-constant-committed`: the JSON hash is anchored in the artifact and also committed into executed contract logic, so it materially affects the compiled program, CMR, and contract address.
|
|
80
|
+
|
|
81
|
+
Today, `on-chain-constant-committed` is guaranteed for custom `.simf` contracts that include the blessed `require_definition_anchor()` helper pattern. Built-in presets still default to artifact-only anchors for now.
|
|
82
|
+
The SDK does **not** trust artifact JSON alone for this verdict. `trust.onChainAnchorVerified` only becomes `true` when the SDK can read the source file again and re-detect the blessed helper pattern. If the source file is unavailable, the claimed mode may still be `on-chain-constant-committed`, but `onChainAnchorVerified` will remain `false`.
|
|
83
|
+
|
|
75
84
|
Minimal TypeScript flow:
|
|
76
85
|
|
|
77
86
|
```ts
|
|
@@ -92,6 +101,7 @@ const compiled = await sdk.compileFromFile({
|
|
|
92
101
|
id: definition.definitionId,
|
|
93
102
|
schemaVersion: definition.schemaVersion,
|
|
94
103
|
jsonPath: definition.sourcePath,
|
|
104
|
+
anchorMode: "on-chain-constant-committed",
|
|
95
105
|
},
|
|
96
106
|
artifactPath: "./bond.artifact.json",
|
|
97
107
|
});
|
|
@@ -104,6 +114,7 @@ const verification = await sdk.verifyDefinitionAgainstArtifact({
|
|
|
104
114
|
});
|
|
105
115
|
|
|
106
116
|
console.log(verification.ok);
|
|
117
|
+
console.log(verification.trust.effectiveMode);
|
|
107
118
|
```
|
|
108
119
|
|
|
109
120
|
CLI equivalents:
|
|
@@ -828,6 +839,7 @@ When you compile with `definition: { ... }`, the artifact also carries:
|
|
|
828
839
|
- `schemaVersion`
|
|
829
840
|
- `hash`
|
|
830
841
|
- `trustMode`
|
|
842
|
+
- `anchorMode`
|
|
831
843
|
|
|
832
844
|
That is what allows the SDK and CLI to verify that an off-chain JSON definition still matches the contract you compiled.
|
|
833
845
|
|
package/dist/cli.js
CHANGED
|
@@ -72,7 +72,8 @@ function parseDefinitionInput() {
|
|
|
72
72
|
const jsonPath = getArg("definition-json");
|
|
73
73
|
const valueJson = getArg("definition-value");
|
|
74
74
|
const schemaVersion = getArg("definition-schema-version");
|
|
75
|
-
|
|
75
|
+
const anchorMode = getArg("definition-anchor-mode");
|
|
76
|
+
if (!type && !id && !jsonPath && !valueJson && !schemaVersion && !anchorMode) {
|
|
76
77
|
return undefined;
|
|
77
78
|
}
|
|
78
79
|
return {
|
|
@@ -81,6 +82,7 @@ function parseDefinitionInput() {
|
|
|
81
82
|
schemaVersion: schemaVersion ?? undefined,
|
|
82
83
|
jsonPath,
|
|
83
84
|
value: valueJson ? JSON.parse(valueJson) : undefined,
|
|
85
|
+
anchorMode,
|
|
84
86
|
};
|
|
85
87
|
}
|
|
86
88
|
function resolveConfig() {
|
|
@@ -382,6 +384,9 @@ function formatArtifactHelp(artifact, preset, utxos) {
|
|
|
382
384
|
` schema version: ${artifact.definition.schemaVersion}`,
|
|
383
385
|
` hash: ${artifact.definition.hash}`,
|
|
384
386
|
` trust mode: ${artifact.definition.trustMode}`,
|
|
387
|
+
` anchor mode: ${artifact.definition.anchorMode}`,
|
|
388
|
+
` on-chain helper: ${artifact.definition.onChainAnchor?.helper ?? "(none)"}`,
|
|
389
|
+
` source verified: ${artifact.definition.onChainAnchor?.sourceVerified === true ? "yes" : "no"}`,
|
|
385
390
|
].join("\n")
|
|
386
391
|
: " (none)";
|
|
387
392
|
const compileSource = artifact.source.simfPath ?? artifact.legacy?.simfTemplatePath ?? "(unknown)";
|
|
@@ -466,7 +471,10 @@ async function main() {
|
|
|
466
471
|
value: getArg("value") ? JSON.parse(getArg("value")) : undefined,
|
|
467
472
|
schemaVersion: getArg("schema-version"),
|
|
468
473
|
});
|
|
469
|
-
printJson(
|
|
474
|
+
printJson({
|
|
475
|
+
...definition,
|
|
476
|
+
anchorRecommendation: "Use --definition-anchor-mode on-chain-constant-committed with a blessed custom .simf helper for on-chain enforcement",
|
|
477
|
+
});
|
|
470
478
|
return;
|
|
471
479
|
}
|
|
472
480
|
if (command === "definition" && subcommand === "verify") {
|
|
@@ -485,6 +493,7 @@ async function main() {
|
|
|
485
493
|
reason: verification.reason,
|
|
486
494
|
definition: verification.definition,
|
|
487
495
|
artifactDefinition: verification.artifactDefinition ?? null,
|
|
496
|
+
trust: verification.trust,
|
|
488
497
|
});
|
|
489
498
|
return;
|
|
490
499
|
}
|
|
@@ -21,5 +21,6 @@ export declare class DeployedContract {
|
|
|
21
21
|
definition: Awaited<ReturnType<typeof verifyDefinitionAgainstArtifact>>["definition"];
|
|
22
22
|
artifactDefinition: ArtifactDefinitionMetadata | null;
|
|
23
23
|
reason?: string;
|
|
24
|
+
trust: Awaited<ReturnType<typeof verifyDefinitionAgainstArtifact>>["trust"];
|
|
24
25
|
}>;
|
|
25
26
|
}
|
package/dist/core/artifact.js
CHANGED
|
@@ -17,7 +17,16 @@ function isArtifactV5(value) {
|
|
|
17
17
|
}
|
|
18
18
|
function normalizeArtifact(artifact, networkDefault = "liquidtestnet") {
|
|
19
19
|
if (artifact.version === exports.SDK_ARTIFACT_VERSION) {
|
|
20
|
-
|
|
20
|
+
const current = artifact;
|
|
21
|
+
return {
|
|
22
|
+
...current,
|
|
23
|
+
definition: current.definition
|
|
24
|
+
? {
|
|
25
|
+
...current.definition,
|
|
26
|
+
anchorMode: current.definition.anchorMode ?? "artifact-hash-anchor",
|
|
27
|
+
}
|
|
28
|
+
: undefined,
|
|
29
|
+
};
|
|
21
30
|
}
|
|
22
31
|
if (!isArtifactV5(artifact)) {
|
|
23
32
|
throw new errors_1.ArtifactError("Unsupported artifact version", artifact);
|
package/dist/core/compiler.js
CHANGED
|
@@ -68,7 +68,12 @@ async function buildArtifact(input) {
|
|
|
68
68
|
sdkVersion: artifact_1.SDK_PACKAGE_VERSION,
|
|
69
69
|
notes: null,
|
|
70
70
|
},
|
|
71
|
-
definition: input.definition
|
|
71
|
+
definition: input.definition
|
|
72
|
+
? (0, definition_1.buildArtifactDefinitionMetadata)(input.definition, {
|
|
73
|
+
anchorMode: input.definition.anchorMode,
|
|
74
|
+
onChainAnchor: input.definition.onChainAnchor,
|
|
75
|
+
})
|
|
76
|
+
: undefined,
|
|
72
77
|
legacy: {
|
|
73
78
|
simfTemplatePath: input.sourceSimfPath,
|
|
74
79
|
params: {
|
|
@@ -80,7 +85,31 @@ async function buildArtifact(input) {
|
|
|
80
85
|
}
|
|
81
86
|
async function compileFromFile(config, input) {
|
|
82
87
|
const definition = input.definition ? await (0, definition_1.loadDefinitionInput)(input.definition) : undefined;
|
|
88
|
+
if (definition && input.templateVars?.DEFINITION_HASH !== undefined) {
|
|
89
|
+
throw new errors_1.ValidationError("DEFINITION_HASH must not be provided explicitly when definition metadata is supplied", { code: "DEFINITION_HASH_OVERRIDE_FORBIDDEN" });
|
|
90
|
+
}
|
|
91
|
+
if (definition && input.templateVars?.DEFINITION_ID !== undefined) {
|
|
92
|
+
throw new errors_1.ValidationError("DEFINITION_ID must not be provided explicitly when definition metadata is supplied", { code: "DEFINITION_ID_OVERRIDE_FORBIDDEN" });
|
|
93
|
+
}
|
|
83
94
|
const rawSource = await (0, promises_1.readFile)(input.simfPath, "utf8");
|
|
95
|
+
let onChainAnchor;
|
|
96
|
+
if (input.definition?.anchorMode === "on-chain-constant-committed") {
|
|
97
|
+
const detection = (0, definition_1.detectOnChainDefinitionAnchor)(rawSource);
|
|
98
|
+
if (!rawSource.includes("{{DEFINITION_HASH}}")) {
|
|
99
|
+
throw new errors_1.ValidationError("Requested on-chain constant-committed definition anchor, but the .simf source does not contain {{DEFINITION_HASH}}", { code: "DEFINITION_HASH_PLACEHOLDER_MISSING" });
|
|
100
|
+
}
|
|
101
|
+
if (!detection.sourceVerified || !detection.helper) {
|
|
102
|
+
const code = detection.reason?.includes("called")
|
|
103
|
+
? "DEFINITION_ONCHAIN_HELPER_NOT_CALLED"
|
|
104
|
+
: "DEFINITION_ONCHAIN_HELPER_MISSING";
|
|
105
|
+
throw new errors_1.ValidationError(`Requested on-chain constant-committed definition anchor, but the .simf source does not contain the required anchor helper pattern: ${detection.reason ?? "unknown reason"}`, { code });
|
|
106
|
+
}
|
|
107
|
+
onChainAnchor = {
|
|
108
|
+
helper: detection.helper,
|
|
109
|
+
templateVar: "DEFINITION_HASH",
|
|
110
|
+
sourceVerified: true,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
84
113
|
const templateVars = {
|
|
85
114
|
...(input.templateVars ?? {}),
|
|
86
115
|
...(definition && input.templateVars?.DEFINITION_HASH === undefined ? { DEFINITION_HASH: definition.hash } : {}),
|
|
@@ -96,7 +125,13 @@ async function compileFromFile(config, input) {
|
|
|
96
125
|
sourceMode: "file",
|
|
97
126
|
sourceSimfPath: input.simfPath,
|
|
98
127
|
templateVars,
|
|
99
|
-
definition
|
|
128
|
+
definition: definition
|
|
129
|
+
? {
|
|
130
|
+
...definition,
|
|
131
|
+
anchorMode: input.definition?.anchorMode ?? "artifact-hash-anchor",
|
|
132
|
+
onChainAnchor,
|
|
133
|
+
}
|
|
134
|
+
: undefined,
|
|
100
135
|
});
|
|
101
136
|
if (input.artifactPath) {
|
|
102
137
|
await (0, artifact_1.saveArtifact)(input.artifactPath, artifact);
|
|
@@ -105,7 +140,16 @@ async function compileFromFile(config, input) {
|
|
|
105
140
|
}
|
|
106
141
|
async function compileFromPreset(config, input) {
|
|
107
142
|
const preset = (0, presets_1.getPresetOrThrow)(input.preset);
|
|
143
|
+
if (input.definition?.anchorMode === "on-chain-constant-committed") {
|
|
144
|
+
throw new errors_1.UnsupportedFeatureError(`Preset '${preset.id}' does not yet support on-chain constant-committed definition anchors`, { code: "DEFINITION_ANCHOR_MODE_UNSUPPORTED_FOR_PRESET", preset: preset.id });
|
|
145
|
+
}
|
|
108
146
|
const definition = input.definition ? await (0, definition_1.loadDefinitionInput)(input.definition) : undefined;
|
|
147
|
+
if (definition && input.params.DEFINITION_HASH !== undefined) {
|
|
148
|
+
throw new errors_1.ValidationError("DEFINITION_HASH must not be provided explicitly when definition metadata is supplied", { code: "DEFINITION_HASH_OVERRIDE_FORBIDDEN" });
|
|
149
|
+
}
|
|
150
|
+
if (definition && input.params.DEFINITION_ID !== undefined) {
|
|
151
|
+
throw new errors_1.ValidationError("DEFINITION_ID must not be provided explicitly when definition metadata is supplied", { code: "DEFINITION_ID_OVERRIDE_FORBIDDEN" });
|
|
152
|
+
}
|
|
109
153
|
const params = {
|
|
110
154
|
...(0, presets_1.validatePresetParams)(preset, input.params),
|
|
111
155
|
...(definition && input.params.DEFINITION_HASH === undefined ? { DEFINITION_HASH: definition.hash } : {}),
|
|
@@ -123,7 +167,12 @@ async function compileFromPreset(config, input) {
|
|
|
123
167
|
sourceSimfPath: preset.simfTemplatePath,
|
|
124
168
|
preset: preset.id,
|
|
125
169
|
templateVars: params,
|
|
126
|
-
definition
|
|
170
|
+
definition: definition
|
|
171
|
+
? {
|
|
172
|
+
...definition,
|
|
173
|
+
anchorMode: input.definition?.anchorMode ?? "artifact-hash-anchor",
|
|
174
|
+
}
|
|
175
|
+
: undefined,
|
|
127
176
|
});
|
|
128
177
|
if (input.artifactPath) {
|
|
129
178
|
await (0, artifact_1.saveArtifact)(input.artifactPath, artifact);
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { ArtifactDefinitionMetadata, DefinitionDescriptor, DefinitionInput, DefinitionVerificationResult, SimplicityArtifact } from "./types";
|
|
1
|
+
import { ArtifactDefinitionMetadata, DefinitionAnchorMode, DefinitionDescriptor, DefinitionInput, DefinitionVerificationResult, SimplicityArtifact } from "./types";
|
|
2
2
|
export declare function loadDefinitionInput(input: DefinitionInput): Promise<DefinitionDescriptor>;
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function detectOnChainDefinitionAnchor(simfSource: string): {
|
|
4
|
+
sourceVerified: boolean;
|
|
5
|
+
helper?: "nonzero-eq_256";
|
|
6
|
+
reason?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function buildArtifactDefinitionMetadata(definition: DefinitionDescriptor, options?: {
|
|
9
|
+
anchorMode?: DefinitionAnchorMode;
|
|
10
|
+
onChainAnchor?: ArtifactDefinitionMetadata["onChainAnchor"];
|
|
11
|
+
}): ArtifactDefinitionMetadata;
|
|
4
12
|
export declare function verifyDefinitionDescriptorAgainstArtifact(definition: DefinitionDescriptor, artifactDefinition?: ArtifactDefinitionMetadata, expectedType?: string, expectedId?: string): DefinitionVerificationResult;
|
|
5
13
|
export declare function verifyDefinitionAgainstArtifact(input: {
|
|
6
14
|
artifact: SimplicityArtifact;
|
package/dist/core/definition.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.loadDefinitionInput = loadDefinitionInput;
|
|
7
|
+
exports.detectOnChainDefinitionAnchor = detectOnChainDefinitionAnchor;
|
|
7
8
|
exports.buildArtifactDefinitionMetadata = buildArtifactDefinitionMetadata;
|
|
8
9
|
exports.verifyDefinitionDescriptorAgainstArtifact = verifyDefinitionDescriptorAgainstArtifact;
|
|
9
10
|
exports.verifyDefinitionAgainstArtifact = verifyDefinitionAgainstArtifact;
|
|
@@ -12,6 +13,35 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
12
13
|
const errors_1 = require("./errors");
|
|
13
14
|
const summary_1 = require("./summary");
|
|
14
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
|
+
}
|
|
15
45
|
function assertNonEmpty(value, fieldName) {
|
|
16
46
|
if (!value || value.trim().length === 0) {
|
|
17
47
|
throw new errors_1.DefinitionError(`${fieldName} must not be empty`);
|
|
@@ -77,22 +107,58 @@ async function loadDefinitionInput(input) {
|
|
|
77
107
|
sourcePath,
|
|
78
108
|
};
|
|
79
109
|
}
|
|
80
|
-
function
|
|
110
|
+
function detectOnChainDefinitionAnchor(simfSource) {
|
|
111
|
+
const source = stripComments(simfSource.replace(/\r\n/g, "\n"));
|
|
112
|
+
if (!source.includes("{{DEFINITION_HASH}}")) {
|
|
113
|
+
return { sourceVerified: false, reason: "DEFINITION_HASH placeholder is missing" };
|
|
114
|
+
}
|
|
115
|
+
const helperBody = extractFunctionBody(source, "require_definition_anchor");
|
|
116
|
+
if (!helperBody) {
|
|
117
|
+
return { sourceVerified: false, reason: "Required anchor helper function is missing" };
|
|
118
|
+
}
|
|
119
|
+
if (!helperBody.includes("let anchored_definition_hash: u256 = 0x{{DEFINITION_HASH}};")) {
|
|
120
|
+
return { sourceVerified: false, reason: "Required anchored_definition_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_definition_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_definition_anchor();")) {
|
|
133
|
+
return { sourceVerified: false, reason: "require_definition_anchor() is not called from main" };
|
|
134
|
+
}
|
|
135
|
+
return { sourceVerified: true, helper: "nonzero-eq_256" };
|
|
136
|
+
}
|
|
137
|
+
function buildArtifactDefinitionMetadata(definition, options) {
|
|
81
138
|
return {
|
|
82
139
|
definitionType: definition.definitionType,
|
|
83
140
|
definitionId: definition.definitionId,
|
|
84
141
|
schemaVersion: definition.schemaVersion,
|
|
85
142
|
hash: definition.hash,
|
|
86
143
|
trustMode: "hash-anchor",
|
|
144
|
+
anchorMode: options?.anchorMode ?? DEFAULT_ANCHOR_MODE,
|
|
145
|
+
onChainAnchor: options?.onChainAnchor,
|
|
87
146
|
};
|
|
88
147
|
}
|
|
89
148
|
function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinition, expectedType, expectedId) {
|
|
149
|
+
const noDefinitionTrust = {
|
|
150
|
+
artifactMatch: false,
|
|
151
|
+
onChainAnchorPresent: false,
|
|
152
|
+
onChainAnchorVerified: false,
|
|
153
|
+
effectiveMode: "none",
|
|
154
|
+
};
|
|
90
155
|
if (expectedType && expectedType !== definition.definitionType) {
|
|
91
156
|
return {
|
|
92
157
|
ok: false,
|
|
93
158
|
reason: `Definition type mismatch: expected=${expectedType} actual=${definition.definitionType}`,
|
|
94
159
|
definition,
|
|
95
160
|
artifactDefinition,
|
|
161
|
+
trust: noDefinitionTrust,
|
|
96
162
|
};
|
|
97
163
|
}
|
|
98
164
|
if (expectedId && expectedId !== definition.definitionId) {
|
|
@@ -101,6 +167,7 @@ function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinitio
|
|
|
101
167
|
reason: `Definition id mismatch: expected=${expectedId} actual=${definition.definitionId}`,
|
|
102
168
|
definition,
|
|
103
169
|
artifactDefinition,
|
|
170
|
+
trust: noDefinitionTrust,
|
|
104
171
|
};
|
|
105
172
|
}
|
|
106
173
|
if (!artifactDefinition) {
|
|
@@ -108,14 +175,22 @@ function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinitio
|
|
|
108
175
|
ok: false,
|
|
109
176
|
reason: "Artifact does not contain definition metadata",
|
|
110
177
|
definition,
|
|
178
|
+
trust: noDefinitionTrust,
|
|
111
179
|
};
|
|
112
180
|
}
|
|
181
|
+
const trust = {
|
|
182
|
+
artifactMatch: false,
|
|
183
|
+
onChainAnchorPresent: artifactDefinition.anchorMode === "on-chain-constant-committed",
|
|
184
|
+
onChainAnchorVerified: false,
|
|
185
|
+
effectiveMode: artifactDefinition.anchorMode,
|
|
186
|
+
};
|
|
113
187
|
if (artifactDefinition.definitionType !== definition.definitionType) {
|
|
114
188
|
return {
|
|
115
189
|
ok: false,
|
|
116
190
|
reason: `Definition type mismatch: artifact=${artifactDefinition.definitionType} actual=${definition.definitionType}`,
|
|
117
191
|
definition,
|
|
118
192
|
artifactDefinition,
|
|
193
|
+
trust,
|
|
119
194
|
};
|
|
120
195
|
}
|
|
121
196
|
if (artifactDefinition.definitionId !== definition.definitionId) {
|
|
@@ -124,6 +199,7 @@ function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinitio
|
|
|
124
199
|
reason: `Definition id mismatch: artifact=${artifactDefinition.definitionId} actual=${definition.definitionId}`,
|
|
125
200
|
definition,
|
|
126
201
|
artifactDefinition,
|
|
202
|
+
trust,
|
|
127
203
|
};
|
|
128
204
|
}
|
|
129
205
|
if (artifactDefinition.schemaVersion !== definition.schemaVersion) {
|
|
@@ -132,6 +208,7 @@ function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinitio
|
|
|
132
208
|
reason: `Definition schemaVersion mismatch: artifact=${artifactDefinition.schemaVersion} actual=${definition.schemaVersion}`,
|
|
133
209
|
definition,
|
|
134
210
|
artifactDefinition,
|
|
211
|
+
trust,
|
|
135
212
|
};
|
|
136
213
|
}
|
|
137
214
|
if (artifactDefinition.hash !== definition.hash) {
|
|
@@ -140,11 +217,63 @@ function verifyDefinitionDescriptorAgainstArtifact(definition, artifactDefinitio
|
|
|
140
217
|
reason: `Definition hash mismatch: artifact=${artifactDefinition.hash} actual=${definition.hash}`,
|
|
141
218
|
definition,
|
|
142
219
|
artifactDefinition,
|
|
220
|
+
trust,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
ok: true,
|
|
225
|
+
definition,
|
|
226
|
+
artifactDefinition,
|
|
227
|
+
trust: {
|
|
228
|
+
...trust,
|
|
229
|
+
artifactMatch: true,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async function resolveDefinitionTrust(artifact, baseTrust) {
|
|
234
|
+
if (!artifact.definition) {
|
|
235
|
+
return {
|
|
236
|
+
artifactMatch: false,
|
|
237
|
+
onChainAnchorPresent: false,
|
|
238
|
+
onChainAnchorVerified: false,
|
|
239
|
+
effectiveMode: "none",
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (artifact.definition.anchorMode !== "on-chain-constant-committed") {
|
|
243
|
+
return baseTrust;
|
|
244
|
+
}
|
|
245
|
+
if (artifact.source.mode !== "file" || !artifact.source.simfPath) {
|
|
246
|
+
return {
|
|
247
|
+
...baseTrust,
|
|
248
|
+
onChainAnchorPresent: true,
|
|
249
|
+
onChainAnchorVerified: false,
|
|
250
|
+
effectiveMode: "on-chain-constant-committed",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const source = await (0, promises_1.readFile)(artifact.source.simfPath, "utf8");
|
|
255
|
+
const detection = detectOnChainDefinitionAnchor(source);
|
|
256
|
+
return {
|
|
257
|
+
...baseTrust,
|
|
258
|
+
onChainAnchorPresent: true,
|
|
259
|
+
onChainAnchorVerified: detection.sourceVerified === true,
|
|
260
|
+
effectiveMode: "on-chain-constant-committed",
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return {
|
|
265
|
+
...baseTrust,
|
|
266
|
+
onChainAnchorPresent: true,
|
|
267
|
+
onChainAnchorVerified: false,
|
|
268
|
+
effectiveMode: "on-chain-constant-committed",
|
|
143
269
|
};
|
|
144
270
|
}
|
|
145
|
-
return { ok: true, definition, artifactDefinition };
|
|
146
271
|
}
|
|
147
272
|
async function verifyDefinitionAgainstArtifact(input) {
|
|
148
273
|
const definition = await loadDefinitionInput(input.definition);
|
|
149
|
-
|
|
274
|
+
const result = verifyDefinitionDescriptorAgainstArtifact(definition, input.artifact.definition, input.expectedType, input.expectedId);
|
|
275
|
+
return {
|
|
276
|
+
...result,
|
|
277
|
+
trust: await resolveDefinitionTrust(input.artifact, result.trust),
|
|
278
|
+
};
|
|
150
279
|
}
|
package/dist/core/executor.js
CHANGED
|
@@ -211,6 +211,7 @@ function buildPsetSummary(decoded, meta) {
|
|
|
211
211
|
id: meta.definitionId ?? null,
|
|
212
212
|
hash: meta.definitionHash ?? null,
|
|
213
213
|
trustMode: meta.definitionTrustMode ?? null,
|
|
214
|
+
anchorMode: meta.definitionAnchorMode ?? null,
|
|
214
215
|
},
|
|
215
216
|
contract: {
|
|
216
217
|
address: meta.contractAddress,
|
|
@@ -302,6 +303,7 @@ async function buildExecutionState(config, artifact, input) {
|
|
|
302
303
|
definitionId: artifact.definition?.definitionId,
|
|
303
304
|
definitionHash: artifact.definition?.hash,
|
|
304
305
|
definitionTrustMode: artifact.definition?.trustMode,
|
|
306
|
+
definitionAnchorMode: artifact.definition?.anchorMode,
|
|
305
307
|
expectedLiquidReceiver: input.expectedLiquidReceiver ?? recipientAddress,
|
|
306
308
|
contractAddress: artifact.compiled.contractAddress,
|
|
307
309
|
cmr: artifact.compiled.cmr,
|
|
@@ -457,6 +459,7 @@ async function executeGaslessContractCall(config, artifact, input) {
|
|
|
457
459
|
definitionId: artifact.definition?.definitionId,
|
|
458
460
|
definitionHash: artifact.definition?.hash,
|
|
459
461
|
definitionTrustMode: artifact.definition?.trustMode,
|
|
462
|
+
definitionAnchorMode: artifact.definition?.anchorMode,
|
|
460
463
|
contractAddress: artifact.compiled.contractAddress,
|
|
461
464
|
cmr: artifact.compiled.cmr,
|
|
462
465
|
internalKey: artifact.compiled.internalKey,
|
|
@@ -648,6 +651,7 @@ async function executeRelayedGaslessContractCall(config, artifact, input, relaye
|
|
|
648
651
|
id: artifact.definition?.definitionId ?? null,
|
|
649
652
|
hash: artifact.definition?.hash ?? null,
|
|
650
653
|
trustMode: artifact.definition?.trustMode ?? null,
|
|
654
|
+
anchorMode: artifact.definition?.anchorMode ?? null,
|
|
651
655
|
},
|
|
652
656
|
contract: {
|
|
653
657
|
address: request.detailedSummary.contract.contractAddress,
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type NetworkName = "liquidtestnet" | "liquidv1" | "regtest";
|
|
2
2
|
export type UtxoPolicy = "smallest_over" | "largest" | "newest";
|
|
3
3
|
export type DefinitionTrustMode = "hash-anchor";
|
|
4
|
+
export type DefinitionAnchorMode = "artifact-hash-anchor" | "on-chain-constant-committed";
|
|
4
5
|
export interface RpcConfig {
|
|
5
6
|
url: string;
|
|
6
7
|
username: string;
|
|
@@ -97,6 +98,7 @@ export interface DefinitionInput {
|
|
|
97
98
|
schemaVersion?: string;
|
|
98
99
|
jsonPath?: string;
|
|
99
100
|
value?: unknown;
|
|
101
|
+
anchorMode?: DefinitionAnchorMode;
|
|
100
102
|
}
|
|
101
103
|
export interface DefinitionDescriptor {
|
|
102
104
|
definitionType: string;
|
|
@@ -112,6 +114,12 @@ export interface ArtifactDefinitionMetadata {
|
|
|
112
114
|
schemaVersion: string;
|
|
113
115
|
hash: string;
|
|
114
116
|
trustMode: DefinitionTrustMode;
|
|
117
|
+
anchorMode: DefinitionAnchorMode;
|
|
118
|
+
onChainAnchor?: {
|
|
119
|
+
helper: "nonzero-eq_256";
|
|
120
|
+
templateVar: "DEFINITION_HASH";
|
|
121
|
+
sourceVerified: boolean;
|
|
122
|
+
};
|
|
115
123
|
}
|
|
116
124
|
export interface DeploymentInfo {
|
|
117
125
|
contractAddress: string;
|
|
@@ -182,6 +190,7 @@ export interface PsetSummary {
|
|
|
182
190
|
id: string | null;
|
|
183
191
|
hash: string | null;
|
|
184
192
|
trustMode: DefinitionTrustMode | null;
|
|
193
|
+
anchorMode: DefinitionAnchorMode | null;
|
|
185
194
|
};
|
|
186
195
|
contract: {
|
|
187
196
|
address: string;
|
|
@@ -255,6 +264,12 @@ export interface DefinitionVerificationResult {
|
|
|
255
264
|
reason?: string;
|
|
256
265
|
definition: DefinitionDescriptor;
|
|
257
266
|
artifactDefinition?: ArtifactDefinitionMetadata;
|
|
267
|
+
trust: {
|
|
268
|
+
artifactMatch: boolean;
|
|
269
|
+
onChainAnchorPresent: boolean;
|
|
270
|
+
onChainAnchorVerified: boolean;
|
|
271
|
+
effectiveMode: "none" | DefinitionAnchorMode;
|
|
272
|
+
};
|
|
258
273
|
}
|
|
259
274
|
export interface WaitForFundingInput {
|
|
260
275
|
minAmountSat?: number;
|