@crediolabs/policy-synth 0.1.4 → 0.1.6
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 +21 -0
- package/dist/codegen/template.js +3 -3
- package/dist/record/decode.d.ts +6 -3
- package/dist/record/decode.js +56 -3
- package/dist/record/freshness.d.ts +14 -1
- package/dist/record/freshness.js +32 -2
- package/dist/record/index.d.ts +11 -0
- package/dist/record/index.js +25 -0
- package/dist/record/movements.d.ts +15 -3
- package/dist/record/movements.js +42 -7
- package/dist/run/index.d.ts +43 -0
- package/dist/run/index.js +222 -0
- package/dist/run/schemas.d.ts +2016 -0
- package/dist/run/schemas.js +223 -0
- package/dist/synth/address.d.ts +7 -0
- package/dist/synth/address.js +12 -0
- package/dist/synth/compose-from-recording.d.ts +4 -3
- package/dist/synth/compose-from-recording.js +16 -6
- package/dist/synth/deny-cases.d.ts +12 -2
- package/dist/synth/deny-cases.js +76 -4
- package/dist/synth/evaluate.js +2 -2
- package/dist/synth/index.d.ts +1 -0
- package/dist/synth/index.js +4 -0
- package/dist/synth/minimize.d.ts +1 -1
- package/dist/synth/minimize.js +3 -3
- package/dist/synth/synthesize-from-recording.d.ts +5 -2
- package/dist/synth/synthesize-from-recording.js +175 -69
- package/dist/types.d.ts +41 -1
- package/dist/types.js +17 -0
- package/dist/verify/simulate.js +18 -2
- package/dist/verify/verify.js +18 -2
- package/dist-cjs/adapters/interpreter/adapter.d.ts +38 -0
- package/dist-cjs/adapters/interpreter/adapter.js +527 -0
- package/dist-cjs/adapters/interpreter/index.d.ts +1 -0
- package/dist-cjs/adapters/interpreter/index.js +8 -0
- package/dist-cjs/adapters/oz/adapter.d.ts +20 -0
- package/dist-cjs/adapters/oz/adapter.js +289 -0
- package/dist-cjs/adapters/oz/index.d.ts +1 -0
- package/dist-cjs/adapters/oz/index.js +8 -0
- package/dist-cjs/codegen/compile-gate.d.ts +33 -0
- package/dist-cjs/codegen/compile-gate.js +123 -0
- package/dist-cjs/codegen/index.d.ts +2 -0
- package/dist-cjs/codegen/index.js +14 -0
- package/dist-cjs/codegen/template.d.ts +18 -0
- package/dist-cjs/codegen/template.js +134 -0
- package/dist-cjs/errors.d.ts +37 -0
- package/dist-cjs/errors.js +3 -0
- package/dist-cjs/index.d.ts +11 -0
- package/dist-cjs/index.js +27 -0
- package/dist-cjs/ir/index.d.ts +1 -0
- package/dist-cjs/ir/index.js +3 -0
- package/dist-cjs/ir/types.d.ts +108 -0
- package/dist-cjs/ir/types.js +12 -0
- package/dist-cjs/mandate/index.d.ts +2 -0
- package/dist-cjs/mandate/index.js +6 -0
- package/dist-cjs/mandate/to-ir.d.ts +3 -0
- package/dist-cjs/mandate/to-ir.js +63 -0
- package/dist-cjs/mandate/types.d.ts +20 -0
- package/dist-cjs/mandate/types.js +9 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/predicate/encode.d.ts +10 -0
- package/dist-cjs/predicate/encode.js +252 -0
- package/dist-cjs/predicate/index.d.ts +1 -0
- package/dist-cjs/predicate/index.js +6 -0
- package/dist-cjs/record/decode.d.ts +79 -0
- package/dist-cjs/record/decode.js +441 -0
- package/dist-cjs/record/freshness.d.ts +30 -0
- package/dist-cjs/record/freshness.js +85 -0
- package/dist-cjs/record/index.d.ts +32 -0
- package/dist-cjs/record/index.js +191 -0
- package/dist-cjs/record/movements.d.ts +32 -0
- package/dist-cjs/record/movements.js +227 -0
- package/dist-cjs/record/rpc.d.ts +22 -0
- package/dist-cjs/record/rpc.js +74 -0
- package/dist-cjs/record/validate.d.ts +22 -0
- package/dist-cjs/record/validate.js +63 -0
- package/dist-cjs/registry/identify.d.ts +11 -0
- package/dist-cjs/registry/identify.js +87 -0
- package/dist-cjs/registry/index.d.ts +3 -0
- package/dist-cjs/registry/index.js +15 -0
- package/dist-cjs/registry/known-addresses.d.ts +16 -0
- package/dist-cjs/registry/known-addresses.js +53 -0
- package/dist-cjs/registry/protocols.d.ts +38 -0
- package/dist-cjs/registry/protocols.js +153 -0
- package/dist-cjs/review-card/builder.d.ts +14 -0
- package/dist-cjs/review-card/builder.js +264 -0
- package/dist-cjs/review-card/conflict.d.ts +40 -0
- package/dist-cjs/review-card/conflict.js +114 -0
- package/dist-cjs/review-card/cross-check.d.ts +11 -0
- package/dist-cjs/review-card/cross-check.js +151 -0
- package/dist-cjs/review-card/index.d.ts +3 -0
- package/dist-cjs/review-card/index.js +10 -0
- package/dist-cjs/run/index.d.ts +43 -0
- package/dist-cjs/run/index.js +237 -0
- package/dist-cjs/run/schemas.d.ts +2016 -0
- package/dist-cjs/run/schemas.js +226 -0
- package/dist-cjs/seams/index.d.ts +1 -0
- package/dist-cjs/seams/index.js +3 -0
- package/dist-cjs/seams/types.d.ts +66 -0
- package/dist-cjs/seams/types.js +12 -0
- package/dist-cjs/synth/address.d.ts +7 -0
- package/dist-cjs/synth/address.js +15 -0
- package/dist-cjs/synth/compose-from-recording.d.ts +65 -0
- package/dist-cjs/synth/compose-from-recording.js +366 -0
- package/dist-cjs/synth/deny-cases.d.ts +22 -0
- package/dist-cjs/synth/deny-cases.js +438 -0
- package/dist-cjs/synth/evaluate.d.ts +39 -0
- package/dist-cjs/synth/evaluate.js +428 -0
- package/dist-cjs/synth/harness.d.ts +16 -0
- package/dist-cjs/synth/harness.js +29 -0
- package/dist-cjs/synth/index.d.ts +10 -0
- package/dist-cjs/synth/index.js +28 -0
- package/dist-cjs/synth/lower.d.ts +23 -0
- package/dist-cjs/synth/lower.js +119 -0
- package/dist-cjs/synth/minimize.d.ts +4 -0
- package/dist-cjs/synth/minimize.js +41 -0
- package/dist-cjs/synth/predicate-literals.d.ts +5 -0
- package/dist-cjs/synth/predicate-literals.js +28 -0
- package/dist-cjs/synth/scope.d.ts +26 -0
- package/dist-cjs/synth/scope.js +81 -0
- package/dist-cjs/synth/synthesize-from-mandate.d.ts +5 -0
- package/dist-cjs/synth/synthesize-from-mandate.js +37 -0
- package/dist-cjs/synth/synthesize-from-recording.d.ts +49 -0
- package/dist-cjs/synth/synthesize-from-recording.js +759 -0
- package/dist-cjs/types.d.ts +311 -0
- package/dist-cjs/types.js +55 -0
- package/dist-cjs/verify/envelope.d.ts +15 -0
- package/dist-cjs/verify/envelope.js +23 -0
- package/dist-cjs/verify/index.d.ts +3 -0
- package/dist-cjs/verify/index.js +8 -0
- package/dist-cjs/verify/simulate.d.ts +31 -0
- package/dist-cjs/verify/simulate.js +261 -0
- package/dist-cjs/verify/verify.d.ts +21 -0
- package/dist-cjs/verify/verify.js +192 -0
- package/package.json +43 -3
- package/src/codegen/template.ts +3 -3
- package/src/contracts/policy-template/OZ_POLICY_TRAIT.md +171 -0
- package/src/record/corpus-fixtures.json +532 -0
- package/src/record/decode.ts +63 -10
- package/src/record/freshness.ts +34 -2
- package/src/record/index.ts +40 -0
- package/src/record/movements.ts +40 -7
- package/src/run/index.ts +277 -0
- package/src/run/schemas.ts +250 -0
- package/src/synth/address.ts +14 -0
- package/src/synth/compose-from-recording.ts +20 -9
- package/src/synth/deny-cases.ts +87 -4
- package/src/synth/evaluate.ts +2 -2
- package/src/synth/index.ts +4 -0
- package/src/synth/minimize.ts +7 -3
- package/src/synth/synthesize-from-recording.ts +200 -68
- package/src/types.ts +37 -1
- package/src/verify/simulate.ts +21 -2
- package/src/verify/verify.ts +21 -2
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './adapters/oz/index.ts';
|
|
2
|
+
export * from './errors.ts';
|
|
3
|
+
export * from './ir/index.ts';
|
|
4
|
+
export * from './mandate/index.ts';
|
|
5
|
+
export * from './predicate/index.ts';
|
|
6
|
+
export * from './record/index.ts';
|
|
7
|
+
export * from './registry/index.ts';
|
|
8
|
+
export * from './review-card/index.ts';
|
|
9
|
+
export * from './seams/index.ts';
|
|
10
|
+
export * from './synth/index.ts';
|
|
11
|
+
export * from './types.ts';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./adapters/oz/index.js"), exports);
|
|
18
|
+
__exportStar(require("./errors.js"), exports);
|
|
19
|
+
__exportStar(require("./ir/index.js"), exports);
|
|
20
|
+
__exportStar(require("./mandate/index.js"), exports);
|
|
21
|
+
__exportStar(require("./predicate/index.js"), exports);
|
|
22
|
+
__exportStar(require("./record/index.js"), exports);
|
|
23
|
+
__exportStar(require("./registry/index.js"), exports);
|
|
24
|
+
__exportStar(require("./review-card/index.js"), exports);
|
|
25
|
+
__exportStar(require("./seams/index.js"), exports);
|
|
26
|
+
__exportStar(require("./synth/index.js"), exports);
|
|
27
|
+
__exportStar(require("./types.js"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { IRCompare, IRCompOp, IRCondition, IRLogic, IRPolicyRule, IRScalarType, IRSelector, IRVecMode, PolicyIR, } from './types.ts';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** Comparison operator. Mirrors NEAR-V2 `CompOp`. */
|
|
2
|
+
export type IRCompOp = 'eq' | 'lt' | 'lte' | 'gt' | 'gte';
|
|
3
|
+
/** Boolean combinator. Mirrors NEAR-V2 `LogicOp`. */
|
|
4
|
+
export type IRLogic = 'and' | 'or';
|
|
5
|
+
/** Vector match mode for a repeated arg. Mirrors NEAR-V2 `VecMode`. */
|
|
6
|
+
export type IRVecMode = 'all' | 'any';
|
|
7
|
+
/** Scalar value type. Mirrors NEAR-V2 `ScValType`, superset for OZ. */
|
|
8
|
+
export type IRScalarType = 'address' | 'i128' | 'u128' | 'u32' | 'u64' | 'i64' | 'symbol' | 'bytes' | 'bool';
|
|
9
|
+
/** WHERE in the authorized call a value is read. NEAR-V2 selectors first, OZ
|
|
10
|
+
* extensions after (an adapter that cannot express an extension flags it). */
|
|
11
|
+
export type IRSelector = {
|
|
12
|
+
kind: 'arg';
|
|
13
|
+
argIndex: number;
|
|
14
|
+
fieldIndex?: number;
|
|
15
|
+
vecMode?: IRVecMode;
|
|
16
|
+
scalarType: IRScalarType;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'calldata';
|
|
19
|
+
offset: number;
|
|
20
|
+
length: number;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'value';
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'amount';
|
|
25
|
+
token: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'window_spent';
|
|
28
|
+
token: string;
|
|
29
|
+
windowSeconds: number;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'invocation_count';
|
|
32
|
+
windowSeconds: number;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'now';
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'valid_until';
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'oracle_price';
|
|
39
|
+
asset: string;
|
|
40
|
+
};
|
|
41
|
+
/** A single comparison leaf. `value` is a decimal/hex string (i128-safe;
|
|
42
|
+
* never a JS number). */
|
|
43
|
+
export interface IRCompare {
|
|
44
|
+
selector: IRSelector;
|
|
45
|
+
operator: IRCompOp;
|
|
46
|
+
value: string;
|
|
47
|
+
}
|
|
48
|
+
/** Condition tree. NEAR-V2 guard/constraint are flat And/Or; the IR allows
|
|
49
|
+
* nesting + `not` + `in` + `eq_seq` so the same IR can later lower to the OZ
|
|
50
|
+
* predicate DSL. Week-1 adapters only lower the flat supported subset and flag
|
|
51
|
+
* the rest. */
|
|
52
|
+
export type IRCondition = {
|
|
53
|
+
op: 'and' | 'or';
|
|
54
|
+
children: IRCondition[];
|
|
55
|
+
} | {
|
|
56
|
+
op: 'not';
|
|
57
|
+
child: IRCondition;
|
|
58
|
+
} | {
|
|
59
|
+
op: 'compare';
|
|
60
|
+
compare: IRCompare;
|
|
61
|
+
} | {
|
|
62
|
+
op: 'in';
|
|
63
|
+
selector: IRSelector;
|
|
64
|
+
values: string[];
|
|
65
|
+
}
|
|
66
|
+
/** Exact ordered sequence equality. The IR-level selector value MUST EQUAL
|
|
67
|
+
* `values` as an ORDERED sequence (e.g. a swap hop `path`). `in` is pure
|
|
68
|
+
* set membership and cannot express order; `eq_seq` is the construct that
|
|
69
|
+
* does. Adapters that cannot express an exact ordered vector (OZ built-ins)
|
|
70
|
+
* flag this as `uncovered` rather than silently dropping it. */
|
|
71
|
+
| {
|
|
72
|
+
op: 'eq_seq';
|
|
73
|
+
selector: IRSelector;
|
|
74
|
+
values: string[];
|
|
75
|
+
};
|
|
76
|
+
export interface IRPolicyRule {
|
|
77
|
+
/** NEAR-V2 roles whitelist (empty = any; owner exempt). */
|
|
78
|
+
roles: string[];
|
|
79
|
+
/** NEAR-V2 scope filter; each field optional (absent = wildcard). */
|
|
80
|
+
scope: {
|
|
81
|
+
chainId?: number;
|
|
82
|
+
contract?: string;
|
|
83
|
+
method?: string;
|
|
84
|
+
};
|
|
85
|
+
/** NEAR-V2 guard (applicability; skip the rule when it fails). */
|
|
86
|
+
guard?: IRCondition;
|
|
87
|
+
/** NEAR-V2 constraint (AND; reject the transaction when any fails). */
|
|
88
|
+
constraints: IRCondition[];
|
|
89
|
+
/** M-of-N approval (OZ threshold primitives). */
|
|
90
|
+
approval?: {
|
|
91
|
+
kind: 'threshold';
|
|
92
|
+
threshold: number;
|
|
93
|
+
weights?: Record<string, number>;
|
|
94
|
+
};
|
|
95
|
+
/** OZ context-rule expiry. */
|
|
96
|
+
expiry?: {
|
|
97
|
+
validUntilLedger?: number;
|
|
98
|
+
validUntilUnixSeconds?: number;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export interface PolicyIR {
|
|
102
|
+
/** NEAR-V2 PolicyChain. */
|
|
103
|
+
chain: 'stellar' | 'evm';
|
|
104
|
+
/** NEAR-V2 DefaultBehavior. OZ context rules are deny-by-default, so
|
|
105
|
+
* `deny_all` is the OZ default fallback when no rule matches. */
|
|
106
|
+
defaultBehavior: 'allow_all' | 'deny_all';
|
|
107
|
+
rules: IRPolicyRule[];
|
|
108
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/ir/types.ts - the PolicyIR ("Policy Tree").
|
|
3
|
+
//
|
|
4
|
+
// `PolicyIR` is the custody-agnostic "Policy Tree" hub (the diagram's Policy
|
|
5
|
+
// Tree) that every CustodyAdapter compiles FROM. It generalizes the NEAR-V2
|
|
6
|
+
// policy schema (roles / scope filter / guard / constraint / comparison leaves /
|
|
7
|
+
// default behaviour) into one chain-neutral shape and extends it with the
|
|
8
|
+
// OZ-only selectors (spend window, oracle price, invocation count, time) so a
|
|
9
|
+
// single IR can serve every backend. NEAR-V2 has no stateful spend window,
|
|
10
|
+
// oracle, time/expiry, or invocation-count; those are marked as OZ extensions
|
|
11
|
+
// below and are only lowered by adapters that declare support for them.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/mandate/index.ts - re-export the Mandate source.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.mandateToPolicyIR = void 0;
|
|
5
|
+
var to_ir_ts_1 = require("./to-ir.js");
|
|
6
|
+
Object.defineProperty(exports, "mandateToPolicyIR", { enumerable: true, get: function () { return to_ir_ts_1.mandateToPolicyIR; } });
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/mandate/to-ir.ts - deterministic lowering of a MandateSpec to a PolicyIR.
|
|
3
|
+
//
|
|
4
|
+
// `mandateToPolicyIR` is pure and total: the same spec always lowers to a
|
|
5
|
+
// byte-identical PolicyIR. No decoding, no inference, no clock. Each mandate
|
|
6
|
+
// field maps to exactly one IR construct:
|
|
7
|
+
// contract/method -> rule.scope
|
|
8
|
+
// spendingLimit -> a `window_spent(token,window) <= limit` compare
|
|
9
|
+
// approvalThreshold-> rule.approval.threshold
|
|
10
|
+
// recipients -> an `in` condition on the recipient arg (flagged as not
|
|
11
|
+
// covered by the OZ adapter; that is expected)
|
|
12
|
+
// expiry -> rule.expiry
|
|
13
|
+
// The top-level default is `deny_all` (OZ context rules are deny-by-default).
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.mandateToPolicyIR = mandateToPolicyIR;
|
|
16
|
+
/** Arg index the recipient allowlist constrains. Pinned to the SEP-41
|
|
17
|
+
* `transfer(from, to, amount)` convention where `to` is arg 1. This condition
|
|
18
|
+
* is flagged as not covered by the OZ adapter (no built-in primitive expresses
|
|
19
|
+
* an arg allowlist), so the index only needs to be deterministic in week-1. */
|
|
20
|
+
const RECIPIENT_ARG_INDEX = 1;
|
|
21
|
+
function mandateToPolicyIR(spec) {
|
|
22
|
+
const scope = { contract: spec.contract };
|
|
23
|
+
if (spec.method !== undefined)
|
|
24
|
+
scope.method = spec.method;
|
|
25
|
+
const constraints = [];
|
|
26
|
+
if (spec.spendingLimit) {
|
|
27
|
+
constraints.push({
|
|
28
|
+
op: 'compare',
|
|
29
|
+
compare: {
|
|
30
|
+
selector: {
|
|
31
|
+
kind: 'window_spent',
|
|
32
|
+
token: spec.spendingLimit.token,
|
|
33
|
+
windowSeconds: spec.spendingLimit.windowSeconds,
|
|
34
|
+
},
|
|
35
|
+
operator: 'lte',
|
|
36
|
+
value: spec.spendingLimit.limit,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (spec.recipients && spec.recipients.length > 0) {
|
|
41
|
+
const selector = {
|
|
42
|
+
kind: 'arg',
|
|
43
|
+
argIndex: RECIPIENT_ARG_INDEX,
|
|
44
|
+
scalarType: 'address',
|
|
45
|
+
};
|
|
46
|
+
constraints.push({ op: 'in', selector, values: [...spec.recipients] });
|
|
47
|
+
}
|
|
48
|
+
const rule = { roles: [], scope, constraints };
|
|
49
|
+
if (spec.approvalThreshold !== undefined) {
|
|
50
|
+
rule.approval = { kind: 'threshold', threshold: spec.approvalThreshold };
|
|
51
|
+
}
|
|
52
|
+
if (spec.expiry) {
|
|
53
|
+
const expiry = {};
|
|
54
|
+
if (spec.expiry.validUntilLedger !== undefined) {
|
|
55
|
+
expiry.validUntilLedger = spec.expiry.validUntilLedger;
|
|
56
|
+
}
|
|
57
|
+
if (spec.expiry.validUntilUnixSeconds !== undefined) {
|
|
58
|
+
expiry.validUntilUnixSeconds = spec.expiry.validUntilUnixSeconds;
|
|
59
|
+
}
|
|
60
|
+
rule.expiry = expiry;
|
|
61
|
+
}
|
|
62
|
+
return { chain: spec.chain, defaultBehavior: 'deny_all', rules: [rule] };
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface MandateSpec {
|
|
2
|
+
chain: 'stellar';
|
|
3
|
+
contract: string;
|
|
4
|
+
method?: string;
|
|
5
|
+
/** -> OZ `spending_limit` primitive. `limit` is an i128 decimal string. */
|
|
6
|
+
spendingLimit?: {
|
|
7
|
+
token: string;
|
|
8
|
+
limit: string;
|
|
9
|
+
windowSeconds: number;
|
|
10
|
+
};
|
|
11
|
+
/** -> OZ `simple_threshold` / `weighted_threshold` primitive. */
|
|
12
|
+
approvalThreshold?: number;
|
|
13
|
+
/** Recipient allowlist -> an `in` arg condition (not covered by an OZ built-in). */
|
|
14
|
+
recipients?: string[];
|
|
15
|
+
/** -> OZ context-rule expiry. */
|
|
16
|
+
expiry?: {
|
|
17
|
+
validUntilLedger?: number;
|
|
18
|
+
validUntilUnixSeconds?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/mandate/types.ts - the deterministic Mandate source.
|
|
3
|
+
//
|
|
4
|
+
// A MandateSpec is a declarative policy statement: "this account may call this
|
|
5
|
+
// contract, spending at most L per window, requiring M approvals, to these
|
|
6
|
+
// recipients, until this expiry". It carries NO transaction to decode, NO
|
|
7
|
+
// parseConfidence, and NO inference - it lowers deterministically to a
|
|
8
|
+
// PolicyIR. It is the clean end-to-end demo path, co-equal with the recorder.
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type PredicateNode } from '../types.ts';
|
|
2
|
+
export interface EncodedPredicate {
|
|
3
|
+
/** base64 of the canonical ScVal XDR of the predicate root. */
|
|
4
|
+
encodedPredicate: string;
|
|
5
|
+
/** sha256 hex digest of the raw XDR bytes (post-canonicalisation). */
|
|
6
|
+
predicateHash: string;
|
|
7
|
+
}
|
|
8
|
+
/** Encode a `PredicateNode` to the canonical ScVal wire format and hash it.
|
|
9
|
+
* Pure function: same input -> byte-identical output every run. */
|
|
10
|
+
export declare function encodePredicate(node: PredicateNode): EncodedPredicate;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/predicate/encode.ts - canonical predicate encoder.
|
|
3
|
+
//
|
|
4
|
+
// Pure function. Maps a `PredicateNode` AST to the canonical ScVal wire format
|
|
5
|
+
// described in `packages/policy-interpreter/INTERPRETER_INSTALL_PARAMS.md`:
|
|
6
|
+
// - every node is a `ScVal::Vec` whose head element is the tag `ScVal::Symbol`
|
|
7
|
+
// - children of `and` / `or` are sorted ascending by their canonical XDR bytes
|
|
8
|
+
// - `in` haystacks are ALWAYS sorted by canonical XDR bytes (pure set
|
|
9
|
+
// membership); an EXACT ordered sequence is expressed as
|
|
10
|
+
// `eq(selector, literal_vec)` where the `literal_vec` element order is
|
|
11
|
+
// preserved verbatim (the order IS the semantic)
|
|
12
|
+
// - `literal_vec` encodes to a bare `ScVal::Vec` of its element encodings;
|
|
13
|
+
// order is preserved, NOT sorted
|
|
14
|
+
// - i128 uses `Int128Parts{hi: Int64 (signed), lo: Uint64 (unsigned)}`,
|
|
15
|
+
// value = hi*2^64 + lo (NOT signed-magnitude)
|
|
16
|
+
// - no `ScMap` anywhere in the predicate
|
|
17
|
+
// - `encodedPredicate = base64(root.toXDR())`,
|
|
18
|
+
// `predicateHash = sha256(raw XDR bytes)` as hex
|
|
19
|
+
//
|
|
20
|
+
// Caps from `PREDICATE_CAPS` are enforced BEFORE returning; a cap breach throws
|
|
21
|
+
// a `ToolError` with the matching error code and `severity: 'error'`.
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.encodePredicate = encodePredicate;
|
|
24
|
+
const node_crypto_1 = require("node:crypto");
|
|
25
|
+
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
26
|
+
const types_ts_1 = require("../types.js");
|
|
27
|
+
const INT64_MAX = (1n << 63n) - 1n;
|
|
28
|
+
const INT64_MIN = -(1n << 63n);
|
|
29
|
+
const UINT64_MAX = (1n << 64n) - 1n;
|
|
30
|
+
/** Encode a `PredicateNode` to the canonical ScVal wire format and hash it.
|
|
31
|
+
* Pure function: same input -> byte-identical output every run. */
|
|
32
|
+
function encodePredicate(node) {
|
|
33
|
+
// --- pass 1: structural cap checks (no encoding needed) ---
|
|
34
|
+
const stats = computeStats(node);
|
|
35
|
+
if (stats.depth > types_ts_1.PREDICATE_CAPS.MAX_DEPTH) {
|
|
36
|
+
throw capError('PREDICATE_TOO_DEEP', `predicate depth ${stats.depth} exceeds MAX_DEPTH ${types_ts_1.PREDICATE_CAPS.MAX_DEPTH}`);
|
|
37
|
+
}
|
|
38
|
+
if (stats.leaves > types_ts_1.PREDICATE_CAPS.MAX_LEAVES) {
|
|
39
|
+
throw capError('TOO_MANY_LEAVES', `predicate leaf count ${stats.leaves} exceeds MAX_LEAVES ${types_ts_1.PREDICATE_CAPS.MAX_LEAVES}`);
|
|
40
|
+
}
|
|
41
|
+
for (const c of stats.inCounts) {
|
|
42
|
+
if (c.count > types_ts_1.PREDICATE_CAPS.MAX_IN_OPERAND_COUNT) {
|
|
43
|
+
throw capError('IN_OPERAND_LIMIT', `\`in\` operand count ${c.count} exceeds MAX_IN_OPERAND_COUNT ${types_ts_1.PREDICATE_CAPS.MAX_IN_OPERAND_COUNT}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Two-round confirmation costs 2 oracle reads per UNIQUE asset referenced.
|
|
47
|
+
const oracleReads = stats.oracleAssets.size * 2;
|
|
48
|
+
if (oracleReads > types_ts_1.PREDICATE_CAPS.MAX_ORACLE_READS) {
|
|
49
|
+
throw capError('PREDICATE_ORACLE_OVER_LIMIT', `oracle reads ${oracleReads} exceed MAX_ORACLE_READS ${types_ts_1.PREDICATE_CAPS.MAX_ORACLE_READS}`);
|
|
50
|
+
}
|
|
51
|
+
// --- pass 2: build + canonicalise the ScVal ---
|
|
52
|
+
const root = encodeNode(node);
|
|
53
|
+
const rawBytes = root.toXDR();
|
|
54
|
+
if (rawBytes.length > types_ts_1.PREDICATE_CAPS.MAX_PREDICATE_BYTES) {
|
|
55
|
+
throw capError('PREDICATE_TOO_LARGE', `predicate bytes ${rawBytes.length} exceed MAX_PREDICATE_BYTES ${types_ts_1.PREDICATE_CAPS.MAX_PREDICATE_BYTES}`);
|
|
56
|
+
}
|
|
57
|
+
const encodedPredicate = rawBytes.toString('base64');
|
|
58
|
+
const predicateHash = (0, node_crypto_1.createHash)('sha256').update(rawBytes).digest('hex');
|
|
59
|
+
return { encodedPredicate, predicateHash };
|
|
60
|
+
}
|
|
61
|
+
function computeStats(node) {
|
|
62
|
+
const inCounts = [];
|
|
63
|
+
const oracleAssets = new Set();
|
|
64
|
+
const { depth, leaves } = walk(node, inCounts, oracleAssets);
|
|
65
|
+
return { depth, leaves, inCounts, oracleAssets };
|
|
66
|
+
}
|
|
67
|
+
function walk(node, inCounts, oracleAssets) {
|
|
68
|
+
switch (node.op) {
|
|
69
|
+
case 'and':
|
|
70
|
+
case 'or': {
|
|
71
|
+
if (node.children.length === 0)
|
|
72
|
+
return { depth: 1, leaves: 0 };
|
|
73
|
+
let maxChildDepth = 0;
|
|
74
|
+
let totalLeaves = 0;
|
|
75
|
+
for (const c of node.children) {
|
|
76
|
+
const child = walk(c, inCounts, oracleAssets);
|
|
77
|
+
if (child.depth > maxChildDepth)
|
|
78
|
+
maxChildDepth = child.depth;
|
|
79
|
+
totalLeaves += child.leaves;
|
|
80
|
+
}
|
|
81
|
+
return { depth: maxChildDepth + 1, leaves: totalLeaves };
|
|
82
|
+
}
|
|
83
|
+
case 'not': {
|
|
84
|
+
const child = walk(node.child, inCounts, oracleAssets);
|
|
85
|
+
return { depth: child.depth + 1, leaves: child.leaves };
|
|
86
|
+
}
|
|
87
|
+
case 'eq':
|
|
88
|
+
case 'lt':
|
|
89
|
+
case 'lte':
|
|
90
|
+
case 'gt':
|
|
91
|
+
case 'gte': {
|
|
92
|
+
collectOracle(node.left, oracleAssets);
|
|
93
|
+
collectOracle(node.right, oracleAssets);
|
|
94
|
+
return { depth: 1, leaves: leafCount(node.left) + leafCount(node.right) };
|
|
95
|
+
}
|
|
96
|
+
case 'in': {
|
|
97
|
+
inCounts.push({ count: node.haystack.length });
|
|
98
|
+
collectOracle(node.needle, oracleAssets);
|
|
99
|
+
let haystackLeaves = 0;
|
|
100
|
+
for (const h of node.haystack) {
|
|
101
|
+
collectOracle(h, oracleAssets);
|
|
102
|
+
haystackLeaves += leafCount(h);
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
depth: 1,
|
|
106
|
+
leaves: leafCount(node.needle) + haystackLeaves,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/** Leaf-count contribution of one PredicateLeaf: 1 for any flat leaf, and the
|
|
112
|
+
* sum of element leaf counts for `literal_vec` so MAX_LEAVES caps see nested
|
|
113
|
+
* vector elements. */
|
|
114
|
+
function leafCount(leaf) {
|
|
115
|
+
if (leaf.kind === 'literal_vec') {
|
|
116
|
+
let total = 1; // the literal_vec itself counts as one leaf node
|
|
117
|
+
for (const el of leaf.elements)
|
|
118
|
+
total += leafCount(el);
|
|
119
|
+
return total;
|
|
120
|
+
}
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
function collectOracle(leaf, oracleAssets) {
|
|
124
|
+
// literal_vec is the only nested leaf; recurse so an oracle_price buried in a
|
|
125
|
+
// vector literal (which the lowering would forbid, but the cap-walker must
|
|
126
|
+
// still see) is counted toward the oracle-read budget.
|
|
127
|
+
if (leaf.kind === 'oracle_price') {
|
|
128
|
+
oracleAssets.add(leaf.asset);
|
|
129
|
+
}
|
|
130
|
+
else if (leaf.kind === 'literal_vec') {
|
|
131
|
+
for (const el of leaf.elements)
|
|
132
|
+
collectOracle(el, oracleAssets);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function encodeNode(node) {
|
|
136
|
+
switch (node.op) {
|
|
137
|
+
case 'and':
|
|
138
|
+
case 'or': {
|
|
139
|
+
const encoded = node.children.map(encodeNode);
|
|
140
|
+
// sort children by their canonical XDR bytes ascending.
|
|
141
|
+
const sorted = sortByCanonicalBytes(encoded);
|
|
142
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol(node.op), stellar_sdk_1.xdr.ScVal.scvVec(sorted)]);
|
|
143
|
+
}
|
|
144
|
+
case 'not': {
|
|
145
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('not'), encodeNode(node.child)]);
|
|
146
|
+
}
|
|
147
|
+
case 'eq':
|
|
148
|
+
case 'lt':
|
|
149
|
+
case 'lte':
|
|
150
|
+
case 'gt':
|
|
151
|
+
case 'gte': {
|
|
152
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol(node.op), encodeLeaf(node.left), encodeLeaf(node.right)]);
|
|
153
|
+
}
|
|
154
|
+
case 'in': {
|
|
155
|
+
const needle = encodeLeaf(node.needle);
|
|
156
|
+
// `in` is PURE set membership: the haystack is ALWAYS sorted by canonical
|
|
157
|
+
// XDR bytes ascending. An exact ordered sequence (e.g. a swap hop path)
|
|
158
|
+
// is expressed as `eq(selector, literal_vec)` where the vec's element
|
|
159
|
+
// order is preserved verbatim (handled in `encodeLeaf(literal_vec)`).
|
|
160
|
+
const haystack = sortByCanonicalBytes(node.haystack.map(encodeLeaf));
|
|
161
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('in'), needle, stellar_sdk_1.xdr.ScVal.scvVec(haystack)]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function encodeLeaf(leaf) {
|
|
166
|
+
switch (leaf.kind) {
|
|
167
|
+
case 'call_contract':
|
|
168
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('call_contract')]);
|
|
169
|
+
case 'call_fn':
|
|
170
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('call_fn')]);
|
|
171
|
+
case 'call_arg':
|
|
172
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('call_arg'), stellar_sdk_1.xdr.ScVal.scvU32(leaf.index)]);
|
|
173
|
+
case 'amount':
|
|
174
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('amount'), scvAddressFromStrkey(leaf.token)]);
|
|
175
|
+
case 'window_spent':
|
|
176
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([
|
|
177
|
+
symbol('window_spent'),
|
|
178
|
+
scvAddressFromStrkey(leaf.token),
|
|
179
|
+
scvU64FromValue(leaf.windowSeconds),
|
|
180
|
+
]);
|
|
181
|
+
case 'now':
|
|
182
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('now')]);
|
|
183
|
+
case 'valid_until':
|
|
184
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('valid_until')]);
|
|
185
|
+
case 'invocation_count_in_window':
|
|
186
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('invocation_count'), scvU64FromValue(leaf.windowSecs)]);
|
|
187
|
+
case 'oracle_price':
|
|
188
|
+
return stellar_sdk_1.xdr.ScVal.scvVec([symbol('oracle_price'), scvAddressFromStrkey(leaf.asset)]);
|
|
189
|
+
case 'literal_address':
|
|
190
|
+
return scvAddressFromStrkey(leaf.value);
|
|
191
|
+
case 'literal_i128':
|
|
192
|
+
return scvI128FromDecimal(leaf.value);
|
|
193
|
+
case 'literal_symbol':
|
|
194
|
+
return stellar_sdk_1.xdr.ScVal.scvSymbol(leaf.value);
|
|
195
|
+
case 'literal_u32':
|
|
196
|
+
return stellar_sdk_1.xdr.ScVal.scvU32(leaf.value);
|
|
197
|
+
case 'literal_u64':
|
|
198
|
+
return scvU64FromValue(leaf.value);
|
|
199
|
+
case 'literal_bytes':
|
|
200
|
+
return stellar_sdk_1.xdr.ScVal.scvBytes(Buffer.from(leaf.value, 'hex'));
|
|
201
|
+
case 'literal_vec':
|
|
202
|
+
// Bare ScVal::Vec of element encodings - order is preserved verbatim
|
|
203
|
+
// because the order IS the semantic (exact ordered sequence equality).
|
|
204
|
+
return stellar_sdk_1.xdr.ScVal.scvVec(leaf.elements.map(encodeLeaf));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function symbol(s) {
|
|
208
|
+
return stellar_sdk_1.xdr.ScVal.scvSymbol(s);
|
|
209
|
+
}
|
|
210
|
+
function sortByCanonicalBytes(values) {
|
|
211
|
+
const pairs = values.map((v) => ({ v, bytes: v.toXDR() }));
|
|
212
|
+
pairs.sort((a, b) => Buffer.compare(a.bytes, b.bytes));
|
|
213
|
+
return pairs.map((p) => p.v);
|
|
214
|
+
}
|
|
215
|
+
function scvAddressFromStrkey(strkey) {
|
|
216
|
+
return stellar_sdk_1.xdr.ScVal.scvAddress(stellar_sdk_1.Address.fromString(strkey).toScAddress());
|
|
217
|
+
}
|
|
218
|
+
function scvU64FromValue(value) {
|
|
219
|
+
// The Uint64 (UnsignedHyper) constructor accepts string | bigint | number;
|
|
220
|
+
// string is safest for values > 2^53.
|
|
221
|
+
return stellar_sdk_1.xdr.ScVal.scvU64(new stellar_sdk_1.xdr.Uint64(String(value)));
|
|
222
|
+
}
|
|
223
|
+
/** Build `ScVal::I128(Int128Parts{hi, lo})` from a signed decimal string.
|
|
224
|
+
* `Int128Parts` encodes the value as `(hi << 64) + lo` with `hi` a SIGNED
|
|
225
|
+
* 64-bit int and `lo` an UNSIGNED 64-bit int (this is NOT signed-magnitude).
|
|
226
|
+
* The inverse split is `hi = v >> 64n` (arithmetic right shift) and
|
|
227
|
+
* `lo = v & 0xFFFF...`. The SDK's `Int64` constructor takes a signed
|
|
228
|
+
* bigint/string/number. */
|
|
229
|
+
function scvI128FromDecimal(decimal) {
|
|
230
|
+
const v = BigInt(decimal);
|
|
231
|
+
const hi = v >> 64n;
|
|
232
|
+
const lo = v & UINT64_MAX;
|
|
233
|
+
// Guard against accidental over-range. Int128Parts.hi must be a valid Int64
|
|
234
|
+
// (-2^63 .. 2^63-1); values outside this range are invalid i128 entirely.
|
|
235
|
+
if (hi < INT64_MIN || hi > INT64_MAX) {
|
|
236
|
+
throw capError('MALFORMED_PREDICATE', `literal_i128 value ${decimal} is outside the Int128 range`);
|
|
237
|
+
}
|
|
238
|
+
if (lo < 0n || lo > UINT64_MAX) {
|
|
239
|
+
throw capError('MALFORMED_PREDICATE', `literal_i128 value ${decimal} has an invalid Int128Parts.lo`);
|
|
240
|
+
}
|
|
241
|
+
return stellar_sdk_1.xdr.ScVal.scvI128(new stellar_sdk_1.xdr.Int128Parts({
|
|
242
|
+
hi: new stellar_sdk_1.xdr.Int64(hi),
|
|
243
|
+
lo: new stellar_sdk_1.xdr.Uint64(lo),
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
function capError(code, message) {
|
|
247
|
+
const err = new Error(message);
|
|
248
|
+
err.code = code;
|
|
249
|
+
err.severity = 'error';
|
|
250
|
+
err.retryable = false;
|
|
251
|
+
throw err;
|
|
252
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type EncodedPredicate, encodePredicate } from './encode.ts';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/predicate/index.ts - re-export the canonical predicate encoder.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.encodePredicate = void 0;
|
|
5
|
+
var encode_ts_1 = require("./encode.js");
|
|
6
|
+
Object.defineProperty(exports, "encodePredicate", { enumerable: true, get: function () { return encode_ts_1.encodePredicate; } });
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { xdr } from '@stellar/stellar-sdk';
|
|
2
|
+
import { type ContractInvocation, type Network, type OnChainEvent, type ParseConfidence, type ScVal, type TokenMovement } from '../types.ts';
|
|
3
|
+
/** Result of decoding an envelope XDR plus the surrounding metadata from
|
|
4
|
+
* `getTransaction` (events + auth entries). All fields are plain JSON; the
|
|
5
|
+
* caller decides how to interpret them. */
|
|
6
|
+
export interface SerializableAuthEntry {
|
|
7
|
+
authorizingAddress: string | null;
|
|
8
|
+
contract: string;
|
|
9
|
+
fn: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DecodedTransaction {
|
|
12
|
+
sourceAccount: string;
|
|
13
|
+
/** Authorising signers from the envelope signatures (hex-encoded ed25519
|
|
14
|
+
* pubkey hints expanded to G... strkeys). The recorder cannot recover the
|
|
15
|
+
* strkey from the 4-byte hint alone; we record the hint bytes hex instead
|
|
16
|
+
* when no full strkey is available. */
|
|
17
|
+
signers: string[];
|
|
18
|
+
invocations: ContractInvocation[];
|
|
19
|
+
/** Raw on-chain events (from getTransaction.events). Used by validate.ts to
|
|
20
|
+
* cross-check the parsed TokenMovement[] and ContractInvocation[]. */
|
|
21
|
+
events: OnChainEvent[];
|
|
22
|
+
/** Plain JSON projection of InvokeHostFunctionOp.auth(). */
|
|
23
|
+
authEntries: SerializableAuthEntry[];
|
|
24
|
+
/** Records that include at least one `ContractInvocation` whose decoded args
|
|
25
|
+
* vector or whose auth-tree contained an opaque ScVal. Empty list = full
|
|
26
|
+
* parseConfidence = 1.0 (modulo unknown contracts). */
|
|
27
|
+
opaqueScVals: ParseConfidence['opaqueScVals'];
|
|
28
|
+
/** Contracts referenced in invocations whose (fn, args) did not match any
|
|
29
|
+
* known protocol ABI. Each unrecognised invocation is recorded separately
|
|
30
|
+
* so the freshness gate stays fail-closed regardless of operation order. */
|
|
31
|
+
unknownContracts: ParseConfidence['unknownContracts'];
|
|
32
|
+
knownContracts: string[];
|
|
33
|
+
ledgerSequence: number;
|
|
34
|
+
}
|
|
35
|
+
/** Decode a TransactionEnvelope XDR (base64) into a fully parsed invocation tree. */
|
|
36
|
+
export declare function decodeEnvelopeXdr(envelopeXdrB64: string, events?: OnChainEvent[], _authEntries?: unknown[], ledgerSequence?: number, knownContracts?: ReadonlySet<string>, network?: Network | null): DecodedTransaction;
|
|
37
|
+
/** Same as `decodeEnvelopeXdr` but accepts an already-decoded envelope. Useful
|
|
38
|
+
* for tests that build the envelope via SDK helpers (no XDR round-trip). */
|
|
39
|
+
export declare function decodeEnvelope(envelope: xdr.TransactionEnvelope, events?: OnChainEvent[], _authEntries?: unknown[], ledgerSequence?: number, knownContracts?: ReadonlySet<string>, network?: Network | null): DecodedTransaction;
|
|
40
|
+
/** Decode an ScAddress (either account or contract) to its strkey form. */
|
|
41
|
+
export declare function decodeScAddressToAnyStrkey(scAddr: xdr.ScAddress): string | null;
|
|
42
|
+
/** Decode an ScAddress to a C... contract strkey. */
|
|
43
|
+
export declare function decodeScAddressToC(scAddr: xdr.ScAddress): string;
|
|
44
|
+
/** Map an arbitrary ScVal into the normalised `ScVal` subset defined in
|
|
45
|
+
* types.ts. Anything outside the subset is wrapped as `{type:'other', value}`
|
|
46
|
+
* AND recorded in `opaqueScVals` so the freshness module can reduce
|
|
47
|
+
* parseConfidence. Recursion is bounded by `MAX_SCVAL_DEPTH` so a
|
|
48
|
+
* hand-crafted nested-vec payload cannot RangeError the JS stack; the
|
|
49
|
+
* over-depth branch is collapsed to a single opaque `depth-exceeded` token
|
|
50
|
+
* (the recorder's parseConfidence gate then fails the recording closed). */
|
|
51
|
+
export declare function scValToSubset(val: xdr.ScVal, path: string, opaqueScVals: ParseConfidence['opaqueScVals'], depth?: number): ScVal;
|
|
52
|
+
/** Convert Int128Parts (hi: Int64, lo: Uint64) to a BigInt.
|
|
53
|
+
* hi is a signed 64-bit value; lo is unsigned. We use the SDK-provided
|
|
54
|
+
* `toString()` form which gives the signed decimal representation of the 64-bit
|
|
55
|
+
* Int64 directly. */
|
|
56
|
+
export declare function i128PartsToBigInt(parts: xdr.Int128Parts): bigint;
|
|
57
|
+
/** Convert UInt128Parts (hi: Uint64, lo: Uint64) to an unsigned BigInt. */
|
|
58
|
+
export declare function u128PartsToBigInt(parts: xdr.UInt128Parts): bigint;
|
|
59
|
+
export declare function u64PartsToBigInt(h: xdr.UnsignedHyper | xdr.Hyper): bigint;
|
|
60
|
+
/** Convert a ScVal to a friendly string for use in OnChainEvent.topics
|
|
61
|
+
* (always-string scalar representation; vectors/bytes are stringified as JSON
|
|
62
|
+
* to keep the field string-typed). */
|
|
63
|
+
export declare function scValToTopicString(val: xdr.ScVal): string;
|
|
64
|
+
/** Build the OnChainEvent[] view from raw contract events. Diagnostic-only:
|
|
65
|
+
* captures the topics + data + emitter contract for the downstream
|
|
66
|
+
* validator. */
|
|
67
|
+
export declare function contractEventsToOnChainEvents(contractEvents: xdr.ContractEvent[][]): OnChainEvent[];
|
|
68
|
+
/** Build the OnChainEvent[] view from TransactionEvent[] (which wraps
|
|
69
|
+
* ContractEvent with a stage). Same shape as above. */
|
|
70
|
+
export declare function transactionEventsToOnChainEvents(txEvents: xdr.TransactionEvent[]): OnChainEvent[];
|
|
71
|
+
/** Tiny typed error so callers can `instanceof DecodeError` without leaking
|
|
72
|
+
* SDK internals. */
|
|
73
|
+
export declare class DecodeError extends Error {
|
|
74
|
+
readonly name = "DecodeError";
|
|
75
|
+
}
|
|
76
|
+
/** Helper used by validate.ts to map a TokenMovement back to a search key
|
|
77
|
+
* without re-parsing (the validate module must cross-check against the raw
|
|
78
|
+
* events, NOT against the parse). */
|
|
79
|
+
export declare function tokenMovementKey(m: TokenMovement): string;
|