@eco-incorp/sauce 0.99.1 → 0.99.2
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/LICENSE.md +29 -0
- package/README.md +69 -249
- package/actions/dist/to-sauce.d.ts.map +1 -1
- package/actions/dist/to-sauce.js +4 -5
- package/dev-tools/README.md +11 -170
- package/docs/README.md +39 -0
- package/docs/api/README.md +71 -0
- package/docs/api/compiler.md +234 -0
- package/docs/api/coverage.md +117 -0
- package/docs/api/routes.md +110 -0
- package/docs/concepts/architecture.md +134 -0
- package/docs/concepts/saucescript.md +172 -0
- package/docs/examples/README.md +34 -0
- package/docs/examples/compile-program.ts +20 -0
- package/docs/examples/evm-execution.ts +59 -0
- package/docs/examples/first-intent.ts +56 -0
- package/docs/examples/protocol-approval.ts +33 -0
- package/docs/guides/builders-and-actions.md +108 -0
- package/docs/guides/compiling.md +264 -0
- package/docs/guides/intents.md +158 -0
- package/docs/guides/nested-intents.md +79 -0
- package/docs/guides/protocols-and-tokens.md +116 -0
- package/docs/guides/quick-start.md +64 -0
- package/docs/guides/solana.md +196 -0
- package/docs/guides/verification.md +253 -0
- package/package.json +9 -4
- package/sdk/dist/artifacts/V12Deployments.json +23 -5
- package/sdk/dist/artifacts/V12RuntimeBytecode.json +1 -1
- package/sdk/dist/artifacts/svm/engine-devnet.so +0 -0
- package/sdk/dist/artifacts/svm/engine-mainnet.so +0 -0
- package/sdk/dist/artifacts/svm/engine-wire-devnet.json +3 -3
- package/sdk/dist/artifacts/svm/engine-wire-mainnet.json +3 -3
- package/sdk/dist/deployments/index.d.ts +14 -46
- package/sdk/dist/deployments/index.d.ts.map +1 -1
- package/sdk/dist/deployments/index.js +22 -47
- package/sdk/dist/deployments/index.js.map +1 -1
- package/sdk/dist/deployments/v12-addresses.d.ts +9 -5
- package/sdk/dist/deployments/v12-addresses.d.ts.map +1 -1
- package/sdk/dist/deployments/v12-addresses.js +5 -6
- package/sdk/dist/deployments/v12-addresses.js.map +1 -1
- package/sdk/dist/deployments/v12.generated.d.ts +3 -3
- package/sdk/dist/deployments/v12.generated.d.ts.map +1 -1
- package/sdk/dist/deployments/v12.generated.js +3 -3
- package/sdk/dist/deployments/v12.generated.js.map +1 -1
- package/sdk/dist/deposit/index.d.ts +28 -102
- package/sdk/dist/deposit/index.d.ts.map +1 -1
- package/sdk/dist/deposit/index.js.map +1 -1
- package/sdk/dist/deposit/params.d.ts +1 -1
- package/sdk/dist/deposit/params.js +2 -2
- package/sdk/dist/deposit/params.js.map +1 -1
- package/sdk/dist/deposit/source.d.ts +1 -1
- package/sdk/dist/deposit/source.d.ts.map +1 -1
- package/sdk/dist/deposit/source.js +18 -33
- package/sdk/dist/deposit/source.js.map +1 -1
- package/sdk/dist/deposit/types.d.ts +5 -4
- package/sdk/dist/deposit/types.d.ts.map +1 -1
- package/sdk/dist/evm/engine.d.ts +32 -0
- package/sdk/dist/evm/engine.d.ts.map +1 -1
- package/sdk/dist/evm/engine.js +2 -0
- package/sdk/dist/evm/engine.js.map +1 -1
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +2 -0
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/plugin/index.d.ts +16 -41
- package/sdk/dist/plugin/index.d.ts.map +1 -1
- package/sdk/dist/plugin/index.js +2 -6
- package/sdk/dist/plugin/index.js.map +1 -1
- package/sdk/dist/recipes/index.js +2 -2
- package/sdk/dist/recipes/settle.sauce.ts +1 -1
- package/sdk/dist/routes/index.d.ts +3 -3
- package/sdk/dist/routes/index.js +3 -3
- package/sdk/dist/routes/intent-dsl.d.ts +23 -10
- package/sdk/dist/routes/intent-dsl.d.ts.map +1 -1
- package/sdk/dist/routes/intent-dsl.js +19 -2
- package/sdk/dist/routes/intent-dsl.js.map +1 -1
- package/sdk/dist/routes/nest.d.ts +23 -0
- package/sdk/dist/routes/nest.d.ts.map +1 -1
- package/sdk/dist/routes/nest.js +2 -4
- package/sdk/dist/routes/nest.js.map +1 -1
- package/sdk/dist/routes/protocol-rewrite.d.ts +2 -2
- package/sdk/dist/routes/protocol-rewrite.d.ts.map +1 -1
- package/sdk/dist/routes/protocol-rewrite.js +19 -35
- package/sdk/dist/routes/protocol-rewrite.js.map +1 -1
- package/sdk/dist/routes/sauce-calls.d.ts +7 -13
- package/sdk/dist/routes/sauce-calls.d.ts.map +1 -1
- package/sdk/dist/routes/sauce-calls.js +6 -11
- package/sdk/dist/routes/sauce-calls.js.map +1 -1
- package/sdk/dist/routes/sauce-route.d.ts +24 -53
- package/sdk/dist/routes/sauce-route.d.ts.map +1 -1
- package/sdk/dist/routes/sauce-route.js +5 -6
- package/sdk/dist/routes/sauce-route.js.map +1 -1
- package/sdk/dist/routes/source-globals.generated.d.ts +931 -0
- package/sdk/dist/routes/source-globals.generated.d.ts.map +1 -0
- package/sdk/dist/routes/source-globals.generated.js +7 -0
- package/sdk/dist/routes/source-globals.generated.js.map +1 -0
- package/sdk/dist/std/token/token.svm.js +19 -14
- package/sdk/dist/svm/cpi-probe.d.ts +1 -1
- package/sdk/dist/svm/cpi-probe.d.ts.map +1 -1
- package/sdk/dist/svm/cpi-probe.js +5 -2
- package/sdk/dist/svm/cpi-probe.js.map +1 -1
- package/sdk/dist/svm/intent.d.ts +12 -40
- package/sdk/dist/svm/intent.d.ts.map +1 -1
- package/sdk/dist/svm/intent.js +22 -66
- package/sdk/dist/svm/intent.js.map +1 -1
- package/sdk/dist/svm/venues/byreal/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/byreal/index.js +4 -1
- package/sdk/dist/svm/venues/byreal/index.js.map +1 -1
- package/sdk/dist/svm/venues/carrot/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/carrot/index.js +4 -0
- package/sdk/dist/svm/venues/carrot/index.js.map +1 -1
- package/sdk/dist/svm/venues/cropper/index.d.ts +1 -1
- package/sdk/dist/svm/venues/cropper/index.js +1 -1
- package/sdk/dist/svm/venues/huma/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/huma/index.js +4 -1
- package/sdk/dist/svm/venues/huma/index.js.map +1 -1
- package/sdk/dist/svm/venues/index.d.ts +1 -0
- package/sdk/dist/svm/venues/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/index.js +1 -0
- package/sdk/dist/svm/venues/index.js.map +1 -1
- package/sdk/dist/svm/venues/math.d.ts +4 -1
- package/sdk/dist/svm/venues/math.d.ts.map +1 -1
- package/sdk/dist/svm/venues/math.js +4 -1
- package/sdk/dist/svm/venues/math.js.map +1 -1
- package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.js +4 -1
- package/sdk/dist/svm/venues/meteora-damm-v1-stable/index.js.map +1 -1
- package/sdk/dist/svm/venues/meteora-damm-v2/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/meteora-damm-v2/index.js +5 -2
- package/sdk/dist/svm/venues/meteora-damm-v2/index.js.map +1 -1
- package/sdk/dist/svm/venues/obric-v2/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/obric-v2/index.js +16 -5
- package/sdk/dist/svm/venues/obric-v2/index.js.map +1 -1
- package/sdk/dist/svm/venues/oracle-exponent.d.ts +82 -0
- package/sdk/dist/svm/venues/oracle-exponent.d.ts.map +1 -0
- package/sdk/dist/svm/venues/oracle-exponent.js +97 -0
- package/sdk/dist/svm/venues/oracle-exponent.js.map +1 -0
- package/sdk/dist/svm/venues/orca-legacy-token-swap/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/orca-legacy-token-swap/index.js +4 -1
- package/sdk/dist/svm/venues/orca-legacy-token-swap/index.js.map +1 -1
- package/sdk/dist/svm/venues/pumpswap/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/pumpswap/index.js +19 -13
- package/sdk/dist/svm/venues/pumpswap/index.js.map +1 -1
- package/sdk/dist/svm/venues/raydium-amm-v4/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/raydium-amm-v4/index.js +4 -1
- package/sdk/dist/svm/venues/raydium-amm-v4/index.js.map +1 -1
- package/sdk/dist/svm/venues/raydium-clmm/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/raydium-clmm/index.js +4 -1
- package/sdk/dist/svm/venues/raydium-clmm/index.js.map +1 -1
- package/sdk/dist/svm/venues/raydium-cp-swap/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/raydium-cp-swap/index.js +4 -1
- package/sdk/dist/svm/venues/raydium-cp-swap/index.js.map +1 -1
- package/sdk/dist/svm/venues/scorch/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/scorch/index.js +4 -1
- package/sdk/dist/svm/venues/scorch/index.js.map +1 -1
- package/sdk/dist/svm/venues/stabble-common.d.ts +1 -1
- package/sdk/dist/svm/venues/stabble-common.js +1 -1
- package/sdk/dist/svm/venues/types.d.ts +4 -1
- package/sdk/dist/svm/venues/types.d.ts.map +1 -1
- package/sdk/dist/svm/venues/woofi/index.d.ts.map +1 -1
- package/sdk/dist/svm/venues/woofi/index.js +4 -0
- package/sdk/dist/svm/venues/woofi/index.js.map +1 -1
- package/sdk/dist/svm/verify.d.ts +27 -133
- package/sdk/dist/svm/verify.d.ts.map +1 -1
- package/sdk/dist/svm/verify.js +72 -139
- package/sdk/dist/svm/verify.js.map +1 -1
- package/sdk/dist/swap/index.d.ts +16 -59
- package/sdk/dist/swap/index.d.ts.map +1 -1
- package/sdk/dist/swap/index.js +16 -59
- package/sdk/dist/swap/index.js.map +1 -1
- package/sdk/dist/token/source.d.ts.map +1 -1
- package/sdk/dist/token/source.js +4 -1
- package/sdk/dist/token/source.js.map +1 -1
- package/sdk/dist/verify/decode.d.ts +6 -6
- package/sdk/dist/verify/decode.js +7 -7
- package/sdk/dist/verify/index.js +2 -2
- package/sdk/dist/verify/intent.js +2 -2
- package/sdk/dist/verify/vectors.d.ts +1 -1
- package/sdk/dist/verify/vectors.d.ts.map +1 -1
- package/sdk/dist/verify/vectors.js +2 -2
- package/sdk/dist/verify/vectors.js.map +1 -1
- package/sdk/dist/verify/wire.d.ts +5 -4
- package/sdk/dist/verify/wire.d.ts.map +1 -1
- package/sdk/dist/verify/wire.js +5 -4
- package/sdk/dist/verify/wire.js.map +1 -1
package/sdk/dist/svm/verify.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Address } from "@solana/kit";
|
|
2
2
|
export { decodePortalCalldataWithAccounts, encodePortalCalldataWithAccounts, extractSvmSettleFromCalls, extractSvmSettleFromIntent, type PortalAccountMeta, type PortalCalldataWithAccounts, type PortalCalldataWithAccountsInput, type BytesInput, type UniversalAddressInput, type SvmIntentCallLike, type SvmIntentLike, type ExtractSvmSettleOptions, type ExtractedSvmSettle, type SvmSettleTarget, } from "./intent.js";
|
|
3
3
|
/**
|
|
4
4
|
* The values a settle program was compiled with. Both are folded into the bytecode, so they are what
|
|
@@ -41,172 +41,66 @@ export interface SvmSettleVerification {
|
|
|
41
41
|
* Never throws for a non-genuine program; returns `{ genuine: false, mismatch }`.
|
|
42
42
|
*/
|
|
43
43
|
export declare function verifySvmSettleProgram(bytecode: Uint8Array, manifest: SettleManifestLike, expected: SvmSettleExpectation): SvmSettleVerification;
|
|
44
|
-
/**
|
|
45
|
-
|
|
44
|
+
/** Released engine CPI wire, or an explicitly selected pre-gate inspection format. */
|
|
45
|
+
export type SvmExecutionWireFormat = "gated-v1" | "legacy-ungated";
|
|
46
46
|
export type SvmSettleAccountLike = string | {
|
|
47
47
|
address?: string;
|
|
48
48
|
pubkey?: string;
|
|
49
49
|
ref?: string;
|
|
50
50
|
};
|
|
51
51
|
export interface SvmSettleExecutionInput {
|
|
52
|
-
/**
|
|
53
|
-
* The instruction data. On the released engine that is the 8-byte discriminator and nothing else:
|
|
54
|
-
* `executeFromAccount` reads account 0's data verbatim, and a settle's params are defines folded
|
|
55
|
-
* into the bytecode. From the recipes split response this is
|
|
56
|
-
* base64-decode(`execution.instructionData`); from an executed instruction it is the raw ix data.
|
|
57
|
-
*/
|
|
52
|
+
/** Raw ENGINE instruction data, not a Kitchen cook instruction. */
|
|
58
53
|
instructionData: Uint8Array;
|
|
59
|
-
/**
|
|
60
|
-
* The instruction's account list — EITHER the user tail alone (`3N+3`, the recipes
|
|
61
|
-
* `execution.accounts[]`) OR the full list with the leading buffer (`3N+4`, a raw instruction). The
|
|
62
|
-
* leading buffer is detected by length and stripped; each entry is a base58 address or an object
|
|
63
|
-
* with `.address`/`.pubkey`.
|
|
64
|
-
*/
|
|
54
|
+
/** Full gated CPI list: [user accounts..., Pot], or [code, user accounts..., Pot] when staged. */
|
|
65
55
|
accounts: readonly SvmSettleAccountLike[];
|
|
56
|
+
/** Defaults to the released gated wire. Legacy mode accepts a user tail or a code-prefixed tail. */
|
|
57
|
+
wireFormat?: SvmExecutionWireFormat;
|
|
58
|
+
}
|
|
59
|
+
/** Parsed derivation material only; this does not validate the Pot PDA or its signature. */
|
|
60
|
+
export interface SvmExecutionGate {
|
|
61
|
+
owner: Address;
|
|
62
|
+
salt: Uint8Array;
|
|
63
|
+
bump: number;
|
|
64
|
+
pot: Address;
|
|
66
65
|
}
|
|
67
66
|
export interface DecodedSvmSettleExecution {
|
|
68
|
-
/**
|
|
69
|
-
* Which engine instruction the calldata is.
|
|
70
|
-
*
|
|
71
|
-
* `execute_and_close` is gone with the pre-release engine, and so are the `pin` and `slice` this
|
|
72
|
-
* used to report: the released engine carries no payload here, so there is nothing on this wire
|
|
73
|
-
* committing to the staged bytecode. **A caller that wants that commitment must read the
|
|
74
|
-
* KITCHEN's `cook_from_account`**, whose `pin` refuses unless the staged bytes hash to it — see
|
|
75
|
-
* `kitchen.ts`. Reporting a pin from here would now always be `undefined`, which reads as "no pin
|
|
76
|
-
* was given" rather than "this wire cannot carry one".
|
|
77
|
-
*/
|
|
78
67
|
instruction: "execute" | "execute_from_account";
|
|
79
|
-
|
|
68
|
+
wireFormat: SvmExecutionWireFormat;
|
|
69
|
+
gate?: SvmExecutionGate;
|
|
70
|
+
codeAccount?: Address;
|
|
80
71
|
escrowCount: number;
|
|
81
|
-
/** The canonical ref order for `escrowCount` — `svmSettleRefs(escrowCount)`. */
|
|
82
72
|
refs: string[];
|
|
83
|
-
/** Each settle account ref → the pubkey attached at that slot, positionally against `refs`. */
|
|
84
73
|
accounts: Record<string, Address>;
|
|
85
|
-
/** True iff a leading bytecode-buffer account was detected in `accounts` and skipped. */
|
|
86
74
|
hadBufferAccount: boolean;
|
|
87
|
-
/**
|
|
88
|
-
* `ref` (a bare address list). Identities are resolved positionally regardless — this only reports
|
|
89
|
-
* whether a caller-supplied label agreed with the slot it landed in. */
|
|
75
|
+
/** Labels are diagnostic; identities always come from account positions. */
|
|
90
76
|
labeledRefsConsistent: boolean | null;
|
|
91
77
|
}
|
|
92
78
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* `svmSettleRefs(N)` slot to the attached pubkey. Consumes the sauce-recipes `split=1` settle sauce
|
|
97
|
-
* (`execution.instructionData` + `execution.accounts[]`) directly, and equally an executed engine
|
|
98
|
-
* instruction (full data + `[buffer, …user]` account list).
|
|
99
|
-
*
|
|
100
|
-
* `minOut`/`splCount` are NOT among the results, and cannot be: they are defines folded into the
|
|
101
|
-
* bytecode, so no amount of reading the calldata recovers them. `verifySvmSettleExecution` establishes
|
|
102
|
-
* them the only way available — by recompiling with the values a caller expects and byte-comparing.
|
|
103
|
-
*
|
|
104
|
-
* What IS here is not trusted either: the header comes from the raw calldata (not from a receipt), and
|
|
105
|
-
* the account identities are resolved positionally against the canonical refs, never from
|
|
106
|
-
* caller-supplied labels — `labeledRefsConsistent` only reports whether a label the caller happened to
|
|
107
|
-
* attach agreed with the slot it landed in.
|
|
108
|
-
*
|
|
109
|
-
* IMPORTANT — this is a STRUCTURAL decode, NOT a genuineness proof. A staged settle's calldata
|
|
110
|
-
* carries no structural signature: any staged Sauce execute with a `3N+3`/`3N+4` account count has
|
|
111
|
-
* this exact shape. So a non-settle execution (or an adversarial decoy) decodes here without error
|
|
112
|
-
* into any staged program at all. To prove the execution actually runs the genuine settle program,
|
|
113
|
-
* use `verifySvmSettleExecution` (or `extractSvmSettleFromIntent`), which ties the calldata to the
|
|
114
|
-
* SDK's own recompiled canonical settle bytecode.
|
|
115
|
-
*
|
|
116
|
-
* The EVM half splits the same two questions the same way — `decodeSettleProgram` is structural and
|
|
117
|
-
* accepts any 362-byte program, `validateSettleProgram` is the genuineness proof — but reaches the
|
|
118
|
-
* second one WITHOUT a compiler: an EVM settle's params ride the payload after the program, so the
|
|
119
|
-
* program is a constant and one `keccak256` settles it. Here they are `defines` folded into the
|
|
120
|
-
* bytecode, which is why this side recompiles.
|
|
79
|
+
* Decode the released engine's 65-byte gate header and full CPI account list.
|
|
80
|
+
* This inspects bytes and positions; it authenticates neither execution nor account roles.
|
|
81
|
+
* A Kitchen instruction has a different layout and must be decoded separately.
|
|
121
82
|
*/
|
|
122
83
|
export declare function decodeSvmSettleExecution(input: SvmSettleExecutionInput): DecodedSvmSettleExecution;
|
|
123
84
|
export interface SvmSettleExecutionVerifyInput extends SvmSettleExecutionInput, SvmSettleExpectation {
|
|
124
|
-
/**
|
|
125
|
-
* OPTIONAL. The compiled settle bytecode this execution runs (from the recipes split response this is
|
|
126
|
-
* base64-decode(`sauces[settleIdx].program.bytecode`); from an eco-solver intent it is
|
|
127
|
-
* base64-decode(`fulfillmentMetadata.svm.sauceStage.buffers[settleIdx].bytecode`)). When supplied, the
|
|
128
|
-
* actual staged bytes are byte-compared to the canonical settle and tied to the pin.
|
|
129
|
-
*
|
|
130
|
-
* A partner usually does NOT have this (only the on-chain `route.calls`), and does not need it: the SDK
|
|
131
|
-
* recompiles the canonical settle itself and proves genuineness via the calldata pin (see below).
|
|
132
|
-
*/
|
|
85
|
+
/** Staged bytes obtained independently from the code account that will execute. */
|
|
133
86
|
bytecode?: Uint8Array;
|
|
134
|
-
/**
|
|
135
|
-
* OPTIONAL. The 32-byte content pin committing to the staged bytes.
|
|
136
|
-
*
|
|
137
|
-
* **Supplied by the caller, not read off this instruction.** It used to be decoded from the
|
|
138
|
-
* engine's own calldata; the released engine's `executeFromAccount` carries no payload, so the
|
|
139
|
-
* commitment lives one layer up — in the KITCHEN's `cook_from_account`, whose `pin` refuses unless
|
|
140
|
-
* the staged bytes hash to it. Read it from that instruction and pass it here.
|
|
141
|
-
*
|
|
142
|
-
* Without it, supplying `bytecode` proves only that YOUR copy is canonical: nothing ties those
|
|
143
|
-
* bytes to the code account this execution actually runs, and the verdict says so rather than
|
|
144
|
-
* calling the execution genuine.
|
|
145
|
-
*/
|
|
87
|
+
/** Caller-supplied SHA-256 pin, normally from the matching Kitchen cook_from_account. */
|
|
146
88
|
pin?: Uint8Array;
|
|
147
89
|
}
|
|
148
|
-
/**
|
|
149
|
-
* How genuineness was established. The verdicts differ in what they actually prove, and the gap
|
|
150
|
-
* between the strongest and the weakest is the whole reason this type is not a boolean.
|
|
151
|
-
*
|
|
152
|
-
* `inline-bytecode` — an `execute`: the program is IN the calldata, and it byte-matches the
|
|
153
|
-
* canonical settle. The bytes verified are the bytes that run, with nothing in between. A pin means
|
|
154
|
-
* nothing on this path (the engine never reads one) and cannot make an inline execution genuine.
|
|
155
|
-
*
|
|
156
|
-
* `bytecode` — an `execute_from_account` where the caller supplied the staged bytes: they match the
|
|
157
|
-
* canonical settle AND the caller's pin ties to them. A pinless calldata commits to nothing, so it
|
|
158
|
-
* is never genuine here however good the bytes are.
|
|
159
|
-
*
|
|
160
|
-
* `caller-asserted-pin` — an `execute_from_account` with no bytecode, whose pin equals
|
|
161
|
-
* `sha256(canonical settle)`. **This is not an on-chain guarantee.** The released engine's
|
|
162
|
-
* `execute_from_account` has no payload, so nothing enforces this pin at execute time; it means
|
|
163
|
-
* "the caller asserts these staged bytes hash to this", and it is only as good as the caller's
|
|
164
|
-
* evidence — a kitchen `cook_from_account` they witnessed. It was named `pin` while documented as
|
|
165
|
-
* engine-enforced, which is precisely the belief that made it dangerous.
|
|
166
|
-
*
|
|
167
|
-
* `none` — no pin and no bytecode. Genuineness cannot be established from structure alone.
|
|
168
|
-
*
|
|
169
|
-
* The instruction's CALLEE is outside every verdict here: an arbitrary program accepting the same
|
|
170
|
-
* discriminator can do whatever it likes — see `ExtractedSvmSettle.target`, whose `program` state a
|
|
171
|
-
* caller must compare against the engine program id it trusts.
|
|
172
|
-
*/
|
|
173
90
|
export type SvmSettleVerifiedBy = "inline-bytecode" | "bytecode" | "caller-asserted-pin" | "none";
|
|
174
91
|
export interface SvmSettleExecutionVerification extends DecodedSvmSettleExecution {
|
|
175
|
-
/**
|
|
92
|
+
/** Program matches the expected settlement; staged results depend on the caller's pin evidence. */
|
|
176
93
|
genuine: boolean;
|
|
177
|
-
/** How `genuine` was established (or why it could not be). */
|
|
178
94
|
verifiedBy: SvmSettleVerifiedBy;
|
|
179
|
-
/** `sha256(canonical recompiled settle)` === the calldata pin. null iff the calldata carried no pin. */
|
|
180
95
|
pinMatchesCanonical: boolean | null;
|
|
181
|
-
/** Only when `bytecode` was supplied: `sha256(bytecode)` === the calldata pin. null otherwise. */
|
|
182
96
|
pinMatchesBytecode: boolean | null;
|
|
183
|
-
/** Only when `bytecode` was supplied: the bytes byte-match the canonical settle. null otherwise. */
|
|
184
97
|
bytecodeMatchesCanonical: boolean | null;
|
|
185
|
-
/** Present iff not genuine: what failed. */
|
|
186
98
|
mismatch?: string;
|
|
187
99
|
}
|
|
188
100
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* bytecode, in one of two ways, no partner bytecode required for either verdict:
|
|
193
|
-
*
|
|
194
|
-
* - `bytecode` supplied → byte-compare it to `compileCanonicalSettle(escrowCount)` AND require the pin
|
|
195
|
-
* to tie to it (`sha256(bytecode) === pin`). Proves the exact staged bytes ARE the settle and WILL run.
|
|
196
|
-
* Both halves are load-bearing: calldata with no pin commits to no program at all, so bytes alone —
|
|
197
|
-
* however genuine — prove nothing about what runs, and the verdict is not genuine.
|
|
198
|
-
* - no bytecode, but a pin was supplied → check `pin === sha256(canonical settle)`. NOTHING ENFORCES
|
|
199
|
-
* THIS ON CHAIN: the released engine's `execute_from_account` has no payload, so this is the
|
|
200
|
-
* caller asserting the staged bytes hash to that value, and it is worth exactly what their
|
|
201
|
-
* evidence is worth — hence `verifiedBy: 'caller-asserted-pin'`.
|
|
202
|
-
* - neither → `genuine: false`, `verifiedBy: 'none'` (structure alone is not proof).
|
|
203
|
-
*
|
|
204
|
-
* An `execute` is handled separately and BEFORE any of the above: its program is inline in the
|
|
205
|
-
* calldata, so it is compared directly and a pin cannot make it genuine.
|
|
206
|
-
*
|
|
207
|
-
* Because `minOut`/`splCount` are folded into the bytecode, a `genuine` result also proves the program
|
|
208
|
-
* enforces the `minOut`/`splCount` passed in — leaving only the resolved account identities for the
|
|
209
|
-
* caller to check. Never throws beyond the shared structural decode; reports failures in `mismatch`.
|
|
101
|
+
* Compare inline bytes, or caller-supplied staged bytes/pin, with a canonical recompile.
|
|
102
|
+
* This does not check the callee, gate derivation/signature, account roles, or transaction success.
|
|
103
|
+
* Engine calldata has no staged content pin; the caller must connect its pin to the code account.
|
|
210
104
|
*/
|
|
211
105
|
export declare function verifySvmSettleExecution(input: SvmSettleExecutionVerifyInput): SvmSettleExecutionVerification;
|
|
212
106
|
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/svm/verify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/svm/verify.ts"],"names":[],"mappings":"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"}
|
package/sdk/dist/svm/verify.js
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// VERIFICATION IS BY RECOMPILE, on both VMs. A settle program's per-execution values
|
|
5
|
-
// (`minOut`, `splCount`) are compile-time `defines`, constant-folded into the bytecode, and every
|
|
6
|
-
// account identity is an attach slot that never appears in it. So there is nothing to decode OUT of
|
|
7
|
-
// a program — and nothing that needs to be: a caller checking an execution already knows the values
|
|
8
|
-
// it expects. What it needs is proof that the program it was handed IS the one those values produce.
|
|
9
|
-
//
|
|
10
|
-
// `verifySvmSettleProgram` is that proof: recompile `svmSettleSource(N)` with the expected defines
|
|
11
|
-
// and byte-compare. A match establishes THREE things at once — the logic is the genuine settle
|
|
12
|
-
// logic, `minOut` is the expected floor, and `splCount` is the expected token-program split —
|
|
13
|
-
// because all three are folded into the same bytes. Under the older staged form the blob was a pure
|
|
14
|
-
// function of N and the scalars rode the instruction payload, so they had to be decoded and checked
|
|
15
|
-
// separately; binding them into the program is strictly stronger.
|
|
16
|
-
//
|
|
17
|
-
// The account identities are never in the bytecode on SVM in either form — Solana requires them
|
|
18
|
-
// attached — so they come from the executed instruction's account list, matched positionally against
|
|
19
|
-
// `svmSettleRefs(N)`. `decodeSvmSettleExecution` does that half; `verifySvmSettleExecution` adds the
|
|
20
|
-
// recompile check and the pin↔bytecode tie.
|
|
21
|
-
//
|
|
22
|
-
// Unlike `@eco-incorp/sauce/verify`, this pulls the compiler in to recompile — a node-side check.
|
|
1
|
+
// SVM settlement identity is checked by recompiling the expected parameters. Account addresses
|
|
2
|
+
// come from the instruction separately; successful verification does not authenticate execution.
|
|
23
3
|
import { createHash } from "node:crypto";
|
|
4
|
+
import { address, getAddressDecoder } from "@solana/kit";
|
|
24
5
|
import { compileWithRs } from "../routes/rs-compile.js";
|
|
25
6
|
import { EXECUTE_DISCRIMINATOR, EXECUTE_FROM_ACCOUNT_DISCRIMINATOR } from "./engine.js";
|
|
26
7
|
import { SVM_MAX_ESCROWS, svmSettleRefs, svmSettleSource } from "./recipes/index.js";
|
|
@@ -100,100 +81,87 @@ export function verifySvmSettleProgram(bytecode, manifest, expected) {
|
|
|
100
81
|
}
|
|
101
82
|
return { genuine: true, escrowCount, refs };
|
|
102
83
|
}
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
const GATED_PROGRAM_OFFSET = 8 + 32 + 32 + 1;
|
|
85
|
+
function accountAddress(account, index) {
|
|
86
|
+
const raw = typeof account === "string" ? account : (account.address ?? account.pubkey);
|
|
105
87
|
if (typeof raw !== "string" || raw.length === 0) {
|
|
106
|
-
throw new Error(
|
|
88
|
+
throw new Error("account " + index + " is not an address (expected a base58 string, or .address/.pubkey)");
|
|
107
89
|
}
|
|
108
|
-
return raw;
|
|
90
|
+
return address(raw);
|
|
109
91
|
}
|
|
110
|
-
|
|
111
|
-
* tail with the leading bytecode-buffer account. Returns null for any other length (the two never
|
|
112
|
-
* collide — `3N+3 = 3M+4` has no integer solution). */
|
|
113
|
-
function classifyAccountList(length) {
|
|
114
|
-
for (const hasBuffer of [false, true]) {
|
|
115
|
-
const userCount = hasBuffer ? length - 1 : length;
|
|
116
|
-
if ((userCount - 3) % 3 !== 0)
|
|
117
|
-
continue;
|
|
118
|
-
const escrowCount = (userCount - 3) / 3;
|
|
119
|
-
if (Number.isInteger(escrowCount) && escrowCount >= 1 && escrowCount <= SVM_MAX_ESCROWS) {
|
|
120
|
-
return { escrowCount, hasBuffer };
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Names the engine instruction from its discriminator alone.
|
|
127
|
-
*
|
|
128
|
-
* Replaces a parser for the `[disc][flags][pin?][slice?]` grammar the pre-release engine took here;
|
|
129
|
-
* the released engine has no payload beyond the discriminator, so there is nothing left to parse.
|
|
130
|
-
*/
|
|
131
|
-
function classifyEngineInstruction(data) {
|
|
92
|
+
function engineInstruction(data, wireFormat) {
|
|
132
93
|
if (!(data instanceof Uint8Array))
|
|
133
94
|
throw new Error("instructionData must be a Uint8Array");
|
|
134
|
-
if (
|
|
135
|
-
throw new Error(
|
|
136
|
-
|
|
137
|
-
|
|
95
|
+
if (wireFormat !== "gated-v1" && wireFormat !== "legacy-ungated") {
|
|
96
|
+
throw new Error("unrecognized SVM execution wire format");
|
|
97
|
+
}
|
|
98
|
+
const headerBytes = wireFormat === "gated-v1" ? GATED_PROGRAM_OFFSET : 8;
|
|
99
|
+
if (data.length < headerBytes) {
|
|
100
|
+
throw new Error("instructionData requires at least " + headerBytes + " bytes for " + wireFormat);
|
|
101
|
+
}
|
|
102
|
+
const discriminator = data.subarray(0, 8);
|
|
103
|
+
if (bytesEqual(discriminator, EXECUTE_FROM_ACCOUNT_DISCRIMINATOR)) {
|
|
104
|
+
if (data.length !== headerBytes) {
|
|
105
|
+
throw new Error("execute_from_account does not accept bytes after its header");
|
|
106
|
+
}
|
|
138
107
|
return "execute_from_account";
|
|
139
|
-
|
|
108
|
+
}
|
|
109
|
+
if (bytesEqual(discriminator, EXECUTE_DISCRIMINATOR))
|
|
140
110
|
return "execute";
|
|
141
111
|
throw new Error("instructionData does not begin with a Sauce engine execute discriminator");
|
|
142
112
|
}
|
|
143
113
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* `svmSettleRefs(N)` slot to the attached pubkey. Consumes the sauce-recipes `split=1` settle sauce
|
|
148
|
-
* (`execution.instructionData` + `execution.accounts[]`) directly, and equally an executed engine
|
|
149
|
-
* instruction (full data + `[buffer, …user]` account list).
|
|
150
|
-
*
|
|
151
|
-
* `minOut`/`splCount` are NOT among the results, and cannot be: they are defines folded into the
|
|
152
|
-
* bytecode, so no amount of reading the calldata recovers them. `verifySvmSettleExecution` establishes
|
|
153
|
-
* them the only way available — by recompiling with the values a caller expects and byte-comparing.
|
|
154
|
-
*
|
|
155
|
-
* What IS here is not trusted either: the header comes from the raw calldata (not from a receipt), and
|
|
156
|
-
* the account identities are resolved positionally against the canonical refs, never from
|
|
157
|
-
* caller-supplied labels — `labeledRefsConsistent` only reports whether a label the caller happened to
|
|
158
|
-
* attach agreed with the slot it landed in.
|
|
159
|
-
*
|
|
160
|
-
* IMPORTANT — this is a STRUCTURAL decode, NOT a genuineness proof. A staged settle's calldata
|
|
161
|
-
* carries no structural signature: any staged Sauce execute with a `3N+3`/`3N+4` account count has
|
|
162
|
-
* this exact shape. So a non-settle execution (or an adversarial decoy) decodes here without error
|
|
163
|
-
* into any staged program at all. To prove the execution actually runs the genuine settle program,
|
|
164
|
-
* use `verifySvmSettleExecution` (or `extractSvmSettleFromIntent`), which ties the calldata to the
|
|
165
|
-
* SDK's own recompiled canonical settle bytecode.
|
|
166
|
-
*
|
|
167
|
-
* The EVM half splits the same two questions the same way — `decodeSettleProgram` is structural and
|
|
168
|
-
* accepts any 362-byte program, `validateSettleProgram` is the genuineness proof — but reaches the
|
|
169
|
-
* second one WITHOUT a compiler: an EVM settle's params ride the payload after the program, so the
|
|
170
|
-
* program is a constant and one `keccak256` settles it. Here they are `defines` folded into the
|
|
171
|
-
* bytecode, which is why this side recompiles.
|
|
114
|
+
* Decode the released engine's 65-byte gate header and full CPI account list.
|
|
115
|
+
* This inspects bytes and positions; it authenticates neither execution nor account roles.
|
|
116
|
+
* A Kitchen instruction has a different layout and must be decoded separately.
|
|
172
117
|
*/
|
|
173
118
|
export function decodeSvmSettleExecution(input) {
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
119
|
+
const wireFormat = input.wireFormat ?? "gated-v1";
|
|
120
|
+
const instruction = engineInstruction(input.instructionData, wireFormat);
|
|
121
|
+
const gated = wireFormat === "gated-v1";
|
|
122
|
+
const hasBuffer = gated
|
|
123
|
+
? instruction === "execute_from_account"
|
|
124
|
+
: escrowCountFromPlan(input.accounts.length) === null;
|
|
125
|
+
const prefixCount = hasBuffer ? 1 : 0;
|
|
126
|
+
const suffixCount = gated ? 1 : 0;
|
|
127
|
+
const escrowCount = escrowCountFromPlan(input.accounts.length - prefixCount - suffixCount);
|
|
128
|
+
if (escrowCount === null) {
|
|
129
|
+
throw new Error("account list has " +
|
|
130
|
+
input.accounts.length +
|
|
131
|
+
" accounts: expected 3N+3 settlement accounts" +
|
|
132
|
+
(hasBuffer ? ", a leading code account" : "") +
|
|
133
|
+
(gated ? ", and a trailing Pot" : "") +
|
|
134
|
+
" for an escrow count 1.." +
|
|
135
|
+
SVM_MAX_ESCROWS);
|
|
178
136
|
}
|
|
179
|
-
const
|
|
137
|
+
const userAccounts = input.accounts.slice(prefixCount, input.accounts.length - suffixCount);
|
|
180
138
|
const refs = svmSettleRefs(escrowCount);
|
|
181
|
-
const userAccounts = hasBuffer ? input.accounts.slice(1) : input.accounts;
|
|
182
139
|
const accounts = {};
|
|
183
140
|
let labeledRefsConsistent = true;
|
|
184
|
-
refs.forEach((ref,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (typeof
|
|
188
|
-
if (
|
|
141
|
+
refs.forEach((ref, index) => {
|
|
142
|
+
const account = userAccounts[index];
|
|
143
|
+
accounts[ref] = accountAddress(account, index + prefixCount);
|
|
144
|
+
if (typeof account === "object" && account !== null && typeof account.ref === "string") {
|
|
145
|
+
if (account.ref !== ref)
|
|
189
146
|
labeledRefsConsistent = false;
|
|
190
147
|
}
|
|
191
148
|
else if (labeledRefsConsistent !== false) {
|
|
192
|
-
labeledRefsConsistent = null;
|
|
149
|
+
labeledRefsConsistent = null;
|
|
193
150
|
}
|
|
194
151
|
});
|
|
152
|
+
const gate = gated
|
|
153
|
+
? {
|
|
154
|
+
owner: getAddressDecoder().decode(input.instructionData.subarray(8, 40)),
|
|
155
|
+
salt: input.instructionData.slice(40, 72),
|
|
156
|
+
bump: input.instructionData[72],
|
|
157
|
+
pot: accountAddress(input.accounts[input.accounts.length - 1], input.accounts.length - 1),
|
|
158
|
+
}
|
|
159
|
+
: undefined;
|
|
195
160
|
return {
|
|
196
161
|
instruction,
|
|
162
|
+
wireFormat,
|
|
163
|
+
...(gate ? { gate } : {}),
|
|
164
|
+
...(hasBuffer ? { codeAccount: accountAddress(input.accounts[0], 0) } : {}),
|
|
197
165
|
escrowCount,
|
|
198
166
|
refs,
|
|
199
167
|
accounts,
|
|
@@ -202,35 +170,13 @@ export function decodeSvmSettleExecution(input) {
|
|
|
202
170
|
};
|
|
203
171
|
}
|
|
204
172
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* bytecode, in one of two ways, no partner bytecode required for either verdict:
|
|
209
|
-
*
|
|
210
|
-
* - `bytecode` supplied → byte-compare it to `compileCanonicalSettle(escrowCount)` AND require the pin
|
|
211
|
-
* to tie to it (`sha256(bytecode) === pin`). Proves the exact staged bytes ARE the settle and WILL run.
|
|
212
|
-
* Both halves are load-bearing: calldata with no pin commits to no program at all, so bytes alone —
|
|
213
|
-
* however genuine — prove nothing about what runs, and the verdict is not genuine.
|
|
214
|
-
* - no bytecode, but a pin was supplied → check `pin === sha256(canonical settle)`. NOTHING ENFORCES
|
|
215
|
-
* THIS ON CHAIN: the released engine's `execute_from_account` has no payload, so this is the
|
|
216
|
-
* caller asserting the staged bytes hash to that value, and it is worth exactly what their
|
|
217
|
-
* evidence is worth — hence `verifiedBy: 'caller-asserted-pin'`.
|
|
218
|
-
* - neither → `genuine: false`, `verifiedBy: 'none'` (structure alone is not proof).
|
|
219
|
-
*
|
|
220
|
-
* An `execute` is handled separately and BEFORE any of the above: its program is inline in the
|
|
221
|
-
* calldata, so it is compared directly and a pin cannot make it genuine.
|
|
222
|
-
*
|
|
223
|
-
* Because `minOut`/`splCount` are folded into the bytecode, a `genuine` result also proves the program
|
|
224
|
-
* enforces the `minOut`/`splCount` passed in — leaving only the resolved account identities for the
|
|
225
|
-
* caller to check. Never throws beyond the shared structural decode; reports failures in `mismatch`.
|
|
173
|
+
* Compare inline bytes, or caller-supplied staged bytes/pin, with a canonical recompile.
|
|
174
|
+
* This does not check the callee, gate derivation/signature, account roles, or transaction success.
|
|
175
|
+
* Engine calldata has no staged content pin; the caller must connect its pin to the code account.
|
|
226
176
|
*/
|
|
227
177
|
export function verifySvmSettleExecution(input) {
|
|
228
178
|
const decoded = decodeSvmSettleExecution(input);
|
|
229
179
|
const canonical = compileCanonicalSettle(decoded.escrowCount, input);
|
|
230
|
-
// The CALLER's pin. This instruction has no payload to carry one, and nothing on chain checks it
|
|
231
|
-
// at execute time, so it is an assertion by whoever supplied it — not a guarantee. On the staged
|
|
232
|
-
// path it is the only thing tying the bytes verified here to the bytes that run, which is exactly
|
|
233
|
-
// why the verdict it produces is named `caller-asserted-pin`.
|
|
234
180
|
const pin = input.pin;
|
|
235
181
|
const pinMatchesCanonical = pin === undefined ? null : bytesEqual(sha256(canonical), pin);
|
|
236
182
|
const bytecodeMatchesCanonical = input.bytecode === undefined ? null : bytesEqual(input.bytecode, canonical);
|
|
@@ -240,41 +186,28 @@ export function verifySvmSettleExecution(input) {
|
|
|
240
186
|
let genuine;
|
|
241
187
|
let verifiedBy;
|
|
242
188
|
let mismatch;
|
|
243
|
-
// An inline `execute` carries its program in the calldata, so it is verifiable directly and a pin
|
|
244
|
-
// is irrelevant to it — the engine never reads one. Before this, the branch order below ignored
|
|
245
|
-
// `decoded.instruction` entirely, so an inline execute carrying ARBITRARY bytecode plus
|
|
246
|
-
// `pin = sha256(canonical)` returned `genuine: true`.
|
|
247
189
|
if (decoded.instruction === "execute") {
|
|
248
|
-
const inline = input.instructionData.subarray(8);
|
|
190
|
+
const inline = input.instructionData.subarray(decoded.wireFormat === "gated-v1" ? GATED_PROGRAM_OFFSET : 8);
|
|
249
191
|
const inlineMatchesCanonical = bytesEqual(inline, canonical);
|
|
250
192
|
const suppliedMatchesInline = input.bytecode === undefined ? null : bytesEqual(input.bytecode, inline);
|
|
251
193
|
verifiedBy = "inline-bytecode";
|
|
252
194
|
genuine = inlineMatchesCanonical && suppliedMatchesInline !== false;
|
|
253
195
|
mismatch = !inlineMatchesCanonical
|
|
254
|
-
?
|
|
196
|
+
? "inline execute bytecode does not byte-match svmSettleSource(" + decoded.escrowCount + ")"
|
|
255
197
|
: suppliedMatchesInline === false
|
|
256
198
|
? "supplied bytecode does not match the bytecode inline in this execute"
|
|
257
199
|
: undefined;
|
|
258
|
-
return {
|
|
259
|
-
...decoded,
|
|
260
|
-
genuine,
|
|
261
|
-
verifiedBy,
|
|
262
|
-
pinMatchesCanonical,
|
|
263
|
-
pinMatchesBytecode,
|
|
264
|
-
bytecodeMatchesCanonical,
|
|
265
|
-
mismatch,
|
|
266
|
-
};
|
|
267
200
|
}
|
|
268
|
-
if (input.bytecode !== undefined) {
|
|
201
|
+
else if (input.bytecode !== undefined) {
|
|
269
202
|
verifiedBy = "bytecode";
|
|
270
203
|
genuine = bytecodeMatchesCanonical === true && pinMatchesBytecode === true;
|
|
271
204
|
mismatch =
|
|
272
205
|
bytecodeMatchesCanonical !== true
|
|
273
|
-
?
|
|
206
|
+
? "bytecode does not byte-match svmSettleSource(" + decoded.escrowCount + ")"
|
|
274
207
|
: pinMatchesBytecode === false
|
|
275
|
-
? "
|
|
208
|
+
? "caller pin does not equal sha256(bytecode)"
|
|
276
209
|
: pinMatchesBytecode === null
|
|
277
|
-
? "
|
|
210
|
+
? "caller supplied no pin, so the staged bytes are not tied to this execution"
|
|
278
211
|
: undefined;
|
|
279
212
|
}
|
|
280
213
|
else if (pin !== undefined) {
|
|
@@ -282,13 +215,13 @@ export function verifySvmSettleExecution(input) {
|
|
|
282
215
|
genuine = pinMatchesCanonical === true;
|
|
283
216
|
mismatch = genuine
|
|
284
217
|
? undefined
|
|
285
|
-
:
|
|
218
|
+
: "pin does not match sha256(svmSettleSource(" + decoded.escrowCount + "))";
|
|
286
219
|
}
|
|
287
220
|
else {
|
|
288
221
|
verifiedBy = "none";
|
|
289
222
|
genuine = false;
|
|
290
223
|
mismatch =
|
|
291
|
-
"no
|
|
224
|
+
"no caller pin and no bytecode supplied: staged program identity cannot be established";
|
|
292
225
|
}
|
|
293
226
|
return {
|
|
294
227
|
...decoded,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/svm/verify.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/svm/verify.ts"],"names":[],"mappings":"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"}
|