@crediolabs/policy-synth 0.1.18 → 0.3.0
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 +6 -5
- package/dist/adapters/interpreter/adapter.d.ts +19 -25
- package/dist/adapters/interpreter/adapter.js +54 -487
- package/dist/adapters/interpreter/index.d.ts +1 -1
- package/dist/adapters/interpreter/index.js +1 -1
- package/dist/adapters/oz/adapter.js +1 -15
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -4
- package/dist/install/build-add-context-rule.d.ts +3 -11
- package/dist/install/build-add-context-rule.js +2 -97
- package/dist/install/build-install-policy.d.ts +4 -53
- package/dist/install/build-install-policy.js +44 -123
- package/dist/ir/index.d.ts +1 -1
- package/dist/ir/types.d.ts +7 -76
- package/dist/ir/types.js +0 -2
- package/dist/predicate/decode.d.ts +1 -1
- package/dist/predicate/decode.js +2 -70
- package/dist/predicate/encode.js +45 -229
- package/dist/predicate/from-json.js +1 -42
- package/dist/record/decode.js +3 -8
- package/dist/review-card/builder.d.ts +4 -3
- package/dist/review-card/builder.js +18 -162
- package/dist/review-card/cross-check.js +2 -105
- package/dist/review-card/render-leaf.d.ts +4 -0
- package/dist/review-card/render-leaf.js +47 -0
- package/dist/run/index.d.ts +35 -53
- package/dist/run/index.js +115 -156
- package/dist/run/schemas.d.ts +168 -1650
- package/dist/run/schemas.js +36 -199
- package/dist/seams/types.d.ts +0 -2
- package/dist/simulate/deny-cases.d.ts +26 -0
- package/dist/simulate/deny-cases.js +282 -0
- package/dist/simulate/evaluate.d.ts +18 -0
- package/dist/simulate/evaluate.js +271 -0
- package/dist/simulate/index.d.ts +4 -0
- package/dist/simulate/index.js +8 -0
- package/dist/synth/compose-from-recording.d.ts +24 -51
- package/dist/synth/compose-from-recording.js +120 -282
- package/dist/synth/deny-cases.d.ts +5 -7
- package/dist/synth/deny-cases.js +23 -373
- package/dist/synth/evaluate.d.ts +0 -21
- package/dist/synth/evaluate.js +56 -336
- package/dist/synth/index.d.ts +0 -5
- package/dist/synth/index.js +0 -5
- package/dist/synth/permit-context.d.ts +2 -9
- package/dist/synth/permit-context.js +1 -82
- package/dist/synth/synthesize-from-recording.d.ts +1 -29
- package/dist/synth/synthesize-from-recording.js +41 -356
- package/dist/types.d.ts +8 -60
- package/dist/types.js +5 -2
- package/dist/verify/simulate.d.ts +1 -14
- package/dist/verify/simulate.js +2 -88
- package/dist/verify/verify.d.ts +1 -7
- package/dist/verify/verify.js +0 -8
- package/dist-cjs/adapters/interpreter/adapter.d.ts +19 -25
- package/dist-cjs/adapters/interpreter/adapter.js +56 -489
- package/dist-cjs/adapters/interpreter/index.d.ts +1 -1
- package/dist-cjs/adapters/interpreter/index.js +1 -2
- package/dist-cjs/adapters/oz/adapter.js +1 -15
- package/dist-cjs/errors.d.ts +1 -1
- package/dist-cjs/index.d.ts +1 -4
- package/dist-cjs/index.js +1 -4
- package/dist-cjs/install/build-add-context-rule.d.ts +3 -11
- package/dist-cjs/install/build-add-context-rule.js +1 -96
- package/dist-cjs/install/build-install-policy.d.ts +4 -53
- package/dist-cjs/install/build-install-policy.js +44 -122
- package/dist-cjs/ir/index.d.ts +1 -1
- package/dist-cjs/ir/types.d.ts +7 -76
- package/dist-cjs/ir/types.js +0 -2
- package/dist-cjs/predicate/decode.d.ts +1 -1
- package/dist-cjs/predicate/decode.js +2 -70
- package/dist-cjs/predicate/encode.js +45 -229
- package/dist-cjs/predicate/from-json.js +1 -42
- package/dist-cjs/record/decode.js +3 -8
- package/dist-cjs/review-card/builder.d.ts +4 -3
- package/dist-cjs/review-card/builder.js +23 -167
- package/dist-cjs/review-card/cross-check.js +7 -110
- package/dist-cjs/review-card/render-leaf.d.ts +4 -0
- package/dist-cjs/review-card/render-leaf.js +52 -0
- package/dist-cjs/run/index.d.ts +35 -53
- package/dist-cjs/run/index.js +116 -162
- package/dist-cjs/run/schemas.d.ts +168 -1650
- package/dist-cjs/run/schemas.js +37 -200
- package/dist-cjs/seams/types.d.ts +0 -2
- package/dist-cjs/simulate/deny-cases.d.ts +26 -0
- package/dist-cjs/simulate/deny-cases.js +286 -0
- package/dist-cjs/simulate/evaluate.d.ts +18 -0
- package/dist-cjs/simulate/evaluate.js +274 -0
- package/dist-cjs/simulate/index.d.ts +4 -0
- package/dist-cjs/simulate/index.js +13 -0
- package/dist-cjs/synth/compose-from-recording.d.ts +24 -51
- package/dist-cjs/synth/compose-from-recording.js +120 -282
- package/dist-cjs/synth/deny-cases.d.ts +5 -7
- package/dist-cjs/synth/deny-cases.js +23 -374
- package/dist-cjs/synth/evaluate.d.ts +0 -21
- package/dist-cjs/synth/evaluate.js +57 -337
- package/dist-cjs/synth/index.d.ts +0 -5
- package/dist-cjs/synth/index.js +1 -11
- package/dist-cjs/synth/permit-context.d.ts +2 -9
- package/dist-cjs/synth/permit-context.js +1 -82
- package/dist-cjs/synth/synthesize-from-recording.d.ts +1 -29
- package/dist-cjs/synth/synthesize-from-recording.js +39 -354
- package/dist-cjs/types.d.ts +8 -60
- package/dist-cjs/types.js +6 -3
- package/dist-cjs/verify/simulate.d.ts +1 -14
- package/dist-cjs/verify/simulate.js +2 -88
- package/dist-cjs/verify/verify.d.ts +1 -7
- package/dist-cjs/verify/verify.js +0 -8
- package/package.json +4 -4
- package/src/adapters/interpreter/adapter.ts +76 -572
- package/src/errors.ts +0 -19
- package/src/index.ts +1 -4
- package/src/install/build-add-context-rule.ts +4 -127
- package/src/install/build-install-policy.ts +93 -214
- package/src/predicate/decode.ts +2 -70
- package/src/predicate/encode.ts +49 -261
- package/src/predicate/from-json.ts +1 -43
- package/src/record/decode.ts +3 -8
- package/src/review-card/builder.ts +19 -168
- package/src/review-card/cross-check.ts +3 -105
- package/src/review-card/render-leaf.ts +48 -0
- package/src/run/index.ts +130 -186
- package/src/run/schemas.ts +38 -214
- package/src/simulate/deny-cases.ts +334 -0
- package/src/simulate/evaluate.ts +284 -0
- package/src/simulate/index.ts +11 -0
- package/src/synth/compose-from-recording.ts +148 -347
- package/src/synth/index.ts +0 -13
- package/src/synth/synthesize-from-recording.ts +43 -456
- package/src/types.ts +13 -49
- package/dist/install/build-install-predicate.d.ts +0 -96
- package/dist/install/build-install-predicate.js +0 -444
- package/dist-cjs/install/build-install-predicate.d.ts +0 -96
- package/dist-cjs/install/build-install-predicate.js +0 -479
- package/src/adapters/interpreter/index.ts +0 -8
- package/src/adapters/oz/adapter.ts +0 -376
- package/src/adapters/oz/index.ts +0 -9
- package/src/codegen/compile-gate.ts +0 -167
- package/src/codegen/index.ts +0 -17
- package/src/codegen/template.ts +0 -165
- package/src/ir/index.ts +0 -13
- package/src/ir/types.ts +0 -132
- package/src/mandate/index.ts +0 -4
- package/src/mandate/to-ir.ts +0 -71
- package/src/mandate/types.ts +0 -21
- package/src/seams/index.ts +0 -11
- package/src/seams/types.ts +0 -81
- package/src/synth/deny-cases.ts +0 -663
- package/src/synth/evaluate.ts +0 -613
- package/src/synth/harness.ts +0 -68
- package/src/synth/minimize.ts +0 -48
- package/src/synth/permit-context.ts +0 -136
- package/src/synth/predicate-literals.ts +0 -27
- package/src/synth/synthesize-from-mandate.ts +0 -82
- package/src/verify/envelope.ts +0 -28
- package/src/verify/index.ts +0 -5
- package/src/verify/simulate.ts +0 -311
- package/src/verify/verify.ts +0 -243
package/src/errors.ts
CHANGED
|
@@ -28,7 +28,6 @@ export type ErrorCode =
|
|
|
28
28
|
| 'PREDICATE_TOO_DEEP'
|
|
29
29
|
| 'TOO_MANY_LEAVES'
|
|
30
30
|
| 'IN_OPERAND_LIMIT'
|
|
31
|
-
| 'PREDICATE_ORACLE_OVER_LIMIT'
|
|
32
31
|
| 'POLICY_CAP_EXCEEDED'
|
|
33
32
|
| 'WASM_TOO_LARGE'
|
|
34
33
|
// --- interpreter-side denies (canonical names; matches Rust DenyCode) ---
|
|
@@ -44,24 +43,6 @@ export type ErrorCode =
|
|
|
44
43
|
| 'UNSUPPORTED_NODE'
|
|
45
44
|
| 'STATEFUL_BOUND'
|
|
46
45
|
| 'NOT_IN_ALLOWLIST'
|
|
47
|
-
| 'FREQUENCY'
|
|
48
|
-
// A `call_arg >= call_arg_scaled(..)` slippage floor was not met. Distinct
|
|
49
|
-
// from the generic ARG_MISMATCH/STATEFUL_BOUND so a violated swap floor
|
|
50
|
-
// reads as itself on the review card.
|
|
51
|
-
| 'SLIPPAGE_FLOOR'
|
|
52
|
-
// --- oracle denies (fatal evaluator errors) ---
|
|
53
|
-
| 'ORACLE_STALE'
|
|
54
|
-
| 'ORACLE_MISSING'
|
|
55
|
-
| 'ORACLE_NO_CONFIRMATION'
|
|
56
|
-
| 'ORACLE_DEVIATION_EXCEEDED'
|
|
57
|
-
| 'ORACLE_MALFORMED_HISTORY'
|
|
58
|
-
| 'ORACLE_FINGERPRINT_DRIFT'
|
|
59
|
-
| 'ORACLE_PAUSED'
|
|
60
|
-
| 'ORACLE_LEAF_INVALID_POSITION'
|
|
61
|
-
| 'ORACLE_PARAMS_OUT_OF_RANGE'
|
|
62
|
-
| 'ORACLE_DECIMALS_MISMATCH'
|
|
63
|
-
| 'ORACLE_THRESHOLD_DECIMALS_OUT_OF_RANGE'
|
|
64
|
-
| 'ORACLE_THRESHOLD_BASIS_REQUIRED'
|
|
65
46
|
// --- escape-hatch compile gate ---
|
|
66
47
|
| 'COMPILE_OK'
|
|
67
48
|
| 'COMPILE_GATE_FAILED'
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
export * from './adapters/oz/index.ts'
|
|
2
1
|
export * from './errors.ts'
|
|
3
|
-
export * from './ir/index.ts'
|
|
4
|
-
export * from './mandate/index.ts'
|
|
5
2
|
export * from './predicate/index.ts'
|
|
6
3
|
export * from './record/index.ts'
|
|
7
4
|
export * from './registry/index.ts'
|
|
8
5
|
export * from './review-card/index.ts'
|
|
9
|
-
export * from './
|
|
6
|
+
export * from './simulate/index.ts'
|
|
10
7
|
export * from './synth/index.ts'
|
|
11
8
|
export * from './types.ts'
|
|
@@ -52,8 +52,8 @@ import { Address, xdr } from '@stellar/stellar-sdk'
|
|
|
52
52
|
import type { ToolError } from '../errors.ts'
|
|
53
53
|
import {
|
|
54
54
|
type ContextRuleDraft,
|
|
55
|
+
GRAMMAR_VERSION,
|
|
55
56
|
OZ_LIMITS,
|
|
56
|
-
type OZPrimitiveConfig,
|
|
57
57
|
type PolicyRef,
|
|
58
58
|
type SignerDraft,
|
|
59
59
|
} from '../types.ts'
|
|
@@ -66,8 +66,8 @@ export interface BuildAddContextRuleArgs {
|
|
|
66
66
|
* admin session. The deployer signs the install call via the admin rule
|
|
67
67
|
* already on the account, which is separate from this list. */
|
|
68
68
|
signers: SignerDraft[]
|
|
69
|
-
/** The policy(ies) to attach to the new rule.
|
|
70
|
-
*
|
|
69
|
+
/** The policy(ies) to attach to the new rule. `interpreter` is the only
|
|
70
|
+
* kind: the OpenZeppelin built-in backend was removed. */
|
|
71
71
|
policies: PolicyRef[]
|
|
72
72
|
/** Per-policy install nonce; 1 for a fresh install. */
|
|
73
73
|
installNonce: number
|
|
@@ -77,20 +77,12 @@ export interface BuildAddContextRuleArgs {
|
|
|
77
77
|
encodedPredicate: string
|
|
78
78
|
/** Hex sha256 of the canonical predicate XDR bytes. */
|
|
79
79
|
predicateHash: string
|
|
80
|
-
/** Per-policy oracle overrides. Absent on any key uses the wasm default. */
|
|
81
|
-
oracleParams?: {
|
|
82
|
-
maxStalenessSeconds?: number
|
|
83
|
-
maxDeviationBps?: number
|
|
84
|
-
/** Bound between the primary and secondary feeds. Tighten-only against
|
|
85
|
-
* the wasm default, like the other two. */
|
|
86
|
-
maxCrossFeedDeviationBps?: number
|
|
87
|
-
}
|
|
88
80
|
/** Hard pin to the interpreter's wasm grammar. Refusing here fails closed
|
|
89
81
|
* before the chain does; the contract will refuse a mismatch again. */
|
|
90
82
|
grammarVersion?: number
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
export const DEFAULT_GRAMMAR_VERSION =
|
|
85
|
+
export const DEFAULT_GRAMMAR_VERSION = GRAMMAR_VERSION
|
|
94
86
|
|
|
95
87
|
/** The verb `add_context_rule` takes on the wire. */
|
|
96
88
|
export const ADD_CONTEXT_RULE_SYMBOL = 'add_context_rule' as const
|
|
@@ -130,20 +122,6 @@ export function buildAddContextRuleArgs(
|
|
|
130
122
|
'a rule with no signers and no policies is refused at install (NoSignersAndPolicies)'
|
|
131
123
|
)
|
|
132
124
|
}
|
|
133
|
-
// OZ's spending_limit caps spend on the CONTEXT CONTRACT - it takes no
|
|
134
|
-
// token argument - so it refuses a Default rule on chain with a bare
|
|
135
|
-
// #3227. Say which rule shape it needs here, before the encoding, rather
|
|
136
|
-
// than letting the user read a numeric trap.
|
|
137
|
-
if (
|
|
138
|
-
args.policies.some((p) => p.kind === 'oz_builtin' && p.primitive.primitive === 'spending_limit')
|
|
139
|
-
) {
|
|
140
|
-
if (draft.contextRuleType.kind !== 'call_contract') {
|
|
141
|
-
throw limitError(
|
|
142
|
-
'INSTALL_BUILD_FAILED',
|
|
143
|
-
`spending_limit caps spend on the rule's context contract, so the rule must be call_contract-scoped to that token - a "${draft.contextRuleType.kind}" rule is refused on chain (#3227)`
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
125
|
|
|
148
126
|
// ---- 2. context_type encoding ----
|
|
149
127
|
const contextType = encodeContextRuleType(draft.contextRuleType)
|
|
@@ -173,15 +151,6 @@ const POLICY_INSTALL_PARAM_FIELDS = [
|
|
|
173
151
|
'install_nonce',
|
|
174
152
|
'predicate',
|
|
175
153
|
'predicate_hash',
|
|
176
|
-
'oracle_max_staleness_seconds',
|
|
177
|
-
'oracle_max_deviation_bps',
|
|
178
|
-
// Cross-feed divergence bound. A field added to the contract's
|
|
179
|
-
// `PolicyInstallParams` changes the ABI: the host unpacks the map by field
|
|
180
|
-
// count, so omitting one fails the entire install with
|
|
181
|
-
// `Error(Object, UnexpectedSize)` and no indication of which field is
|
|
182
|
-
// missing. The Rust tests build that struct in Rust and never cross this
|
|
183
|
-
// boundary, so only a real install against a deployed contract catches it.
|
|
184
|
-
'oracle_max_xfeed_dev_bps',
|
|
185
154
|
] as const
|
|
186
155
|
|
|
187
156
|
function encodeContextRuleType(
|
|
@@ -232,92 +201,12 @@ function encodePoliciesMap(args: BuildAddContextRuleArgs): xdr.ScVal {
|
|
|
232
201
|
val: encodePolicyInstallParams(args),
|
|
233
202
|
})
|
|
234
203
|
)
|
|
235
|
-
} else if (ref.kind === 'oz_builtin') {
|
|
236
|
-
entries.push(
|
|
237
|
-
new xdr.ScMapEntry({
|
|
238
|
-
key: Address.fromString(ref.instanceAddress).toScVal(),
|
|
239
|
-
val: encodeOzPrimitiveParams(ref.primitive),
|
|
240
|
-
})
|
|
241
|
-
)
|
|
242
204
|
}
|
|
243
205
|
}
|
|
244
206
|
entries.sort(sortByScValSymbolString)
|
|
245
207
|
return xdr.ScVal.scvMap(entries)
|
|
246
208
|
}
|
|
247
209
|
|
|
248
|
-
/** Encode the install params for one OZ built-in policy.
|
|
249
|
-
*
|
|
250
|
-
* Field names and types are read from the deployed contracts' own spec:
|
|
251
|
-
* SpendingLimitAccountParams { period_ledgers: u32, spending_limit: i128 }
|
|
252
|
-
* SimpleThresholdAccountParams { threshold: u32 }
|
|
253
|
-
* WeightedThresholdAccountParams { signer_weights: map, threshold: u32 }
|
|
254
|
-
* Entries are symbol-string ordered for the same reason the interpreter's
|
|
255
|
-
* are: the host orders by symbol, not by XDR bytes.
|
|
256
|
-
*/
|
|
257
|
-
function encodeOzPrimitiveParams(primitive: OZPrimitiveConfig): xdr.ScVal {
|
|
258
|
-
const entries: xdr.ScMapEntry[] = []
|
|
259
|
-
const push = (name: string, val: xdr.ScVal) =>
|
|
260
|
-
entries.push(new xdr.ScMapEntry({ key: xdr.ScVal.scvSymbol(name), val }))
|
|
261
|
-
const p = primitive.params as Record<string, unknown>
|
|
262
|
-
switch (primitive.primitive) {
|
|
263
|
-
case 'spending_limit': {
|
|
264
|
-
const limit = p.spending_limit
|
|
265
|
-
const period = p.period_ledgers
|
|
266
|
-
if (typeof limit !== 'string' || typeof period !== 'number') {
|
|
267
|
-
throw limitError(
|
|
268
|
-
'INSTALL_BUILD_FAILED',
|
|
269
|
-
'spending_limit needs { spending_limit: string; period_ledgers: number }'
|
|
270
|
-
)
|
|
271
|
-
}
|
|
272
|
-
push('period_ledgers', xdr.ScVal.scvU32(period))
|
|
273
|
-
push('spending_limit', encodeI128(limit))
|
|
274
|
-
break
|
|
275
|
-
}
|
|
276
|
-
case 'simple_threshold': {
|
|
277
|
-
const threshold = p.threshold
|
|
278
|
-
if (typeof threshold !== 'number') {
|
|
279
|
-
throw limitError('INSTALL_BUILD_FAILED', 'simple_threshold needs { threshold: number }')
|
|
280
|
-
}
|
|
281
|
-
push('threshold', xdr.ScVal.scvU32(threshold))
|
|
282
|
-
break
|
|
283
|
-
}
|
|
284
|
-
case 'weighted_threshold': {
|
|
285
|
-
const threshold = p.threshold
|
|
286
|
-
const weights = p.weights as Record<string, number> | undefined
|
|
287
|
-
if (typeof threshold !== 'number' || !weights) {
|
|
288
|
-
throw limitError(
|
|
289
|
-
'INSTALL_BUILD_FAILED',
|
|
290
|
-
'weighted_threshold needs { threshold: number; weights: Record<address, number> }'
|
|
291
|
-
)
|
|
292
|
-
}
|
|
293
|
-
const weightEntries = Object.entries(weights)
|
|
294
|
-
.map(
|
|
295
|
-
([addr, w]) =>
|
|
296
|
-
new xdr.ScMapEntry({
|
|
297
|
-
key: Address.fromString(addr).toScVal(),
|
|
298
|
-
val: xdr.ScVal.scvU32(w),
|
|
299
|
-
})
|
|
300
|
-
)
|
|
301
|
-
.sort((a, b) => (a.key().toXDR('base64') < b.key().toXDR('base64') ? -1 : 1))
|
|
302
|
-
push('signer_weights', xdr.ScVal.scvMap(weightEntries))
|
|
303
|
-
push('threshold', xdr.ScVal.scvU32(threshold))
|
|
304
|
-
break
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
entries.sort((a, b) => sortBySymbolString(a.key(), b.key()))
|
|
308
|
-
return xdr.ScVal.scvMap(entries)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function encodeI128(value: string): xdr.ScVal {
|
|
312
|
-
const v = BigInt(value)
|
|
313
|
-
return xdr.ScVal.scvI128(
|
|
314
|
-
new xdr.Int128Parts({
|
|
315
|
-
hi: new xdr.Int64(BigInt.asIntN(64, v >> 64n)),
|
|
316
|
-
lo: new xdr.Uint64(BigInt.asUintN(64, v)),
|
|
317
|
-
})
|
|
318
|
-
)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
210
|
function encodePolicyInstallParams(args: BuildAddContextRuleArgs): xdr.ScVal {
|
|
322
211
|
const predicate = Buffer.from(args.encodedPredicate, 'base64')
|
|
323
212
|
const computedHash = createHash('sha256').update(predicate).digest('hex')
|
|
@@ -330,15 +219,11 @@ function encodePolicyInstallParams(args: BuildAddContextRuleArgs): xdr.ScVal {
|
|
|
330
219
|
// Per-field value encoders. Each entry returns the ScVal to drop into the
|
|
331
220
|
// map; the key symbol comes from the surrounding loop. Adding a field is
|
|
332
221
|
// one row here plus the symbol in POLICY_INSTALL_PARAM_FIELDS.
|
|
333
|
-
const oracleParams = args.oracleParams
|
|
334
222
|
const valueFor: Record<(typeof POLICY_INSTALL_PARAM_FIELDS)[number], () => xdr.ScVal> = {
|
|
335
223
|
grammar_version: () => xdr.ScVal.scvU32(args.grammarVersion ?? DEFAULT_GRAMMAR_VERSION),
|
|
336
224
|
install_nonce: () => xdr.ScVal.scvU32(args.installNonce),
|
|
337
225
|
predicate: () => xdr.ScVal.scvBytes(predicate),
|
|
338
226
|
predicate_hash: () => xdr.ScVal.scvBytes(Buffer.from(args.predicateHash, 'hex')),
|
|
339
|
-
oracle_max_staleness_seconds: () => encodeOptionU32(oracleParams?.maxStalenessSeconds),
|
|
340
|
-
oracle_max_deviation_bps: () => encodeOptionU32(oracleParams?.maxDeviationBps),
|
|
341
|
-
oracle_max_xfeed_dev_bps: () => encodeOptionU32(oracleParams?.maxCrossFeedDeviationBps),
|
|
342
227
|
}
|
|
343
228
|
const entries = POLICY_INSTALL_PARAM_FIELDS.map(
|
|
344
229
|
(k) => new xdr.ScMapEntry({ key: xdr.ScVal.scvSymbol(k), val: valueFor[k]() })
|
|
@@ -351,14 +236,6 @@ function encodePolicyInstallParams(args: BuildAddContextRuleArgs): xdr.ScVal {
|
|
|
351
236
|
return xdr.ScVal.scvMap(entries)
|
|
352
237
|
}
|
|
353
238
|
|
|
354
|
-
function encodeOptionU32(v: number | undefined): xdr.ScVal {
|
|
355
|
-
if (v === undefined) return xdr.ScVal.scvVoid()
|
|
356
|
-
if (!Number.isFinite(v) || v < 0 || v > 0xffffffff) {
|
|
357
|
-
throw limitError('INSTALL_BUILD_FAILED', `oracle params value ${v} is outside u32 range`)
|
|
358
|
-
}
|
|
359
|
-
return xdr.ScVal.scvU32(v)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
239
|
/** Sort host-map keys by their symbol-string form. The host orders map
|
|
363
240
|
* entries by the SYMBOL STRING, not by the key's XDR bytes (a length
|
|
364
241
|
* prefix in the encoding would otherwise put `amount` before `address`).
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import { createHash } from 'node:crypto'
|
|
21
21
|
import {
|
|
22
|
+
Account,
|
|
22
23
|
Address,
|
|
23
24
|
BASE_FEE,
|
|
24
25
|
Contract,
|
|
@@ -30,7 +31,8 @@ import {
|
|
|
30
31
|
TransactionBuilder,
|
|
31
32
|
xdr,
|
|
32
33
|
} from '@stellar/stellar-sdk'
|
|
33
|
-
import {
|
|
34
|
+
import type { ContextRuleDraft } from '../types.ts'
|
|
35
|
+
import { buildAddContextRuleArgs } from './build-add-context-rule.ts'
|
|
34
36
|
import {
|
|
35
37
|
accountEntry,
|
|
36
38
|
authDigest,
|
|
@@ -106,20 +108,14 @@ export interface BuildInstallPolicyArgs {
|
|
|
106
108
|
sourceAccount: string
|
|
107
109
|
/** Network passphrase - pins the hash the auth digest binds. */
|
|
108
110
|
networkPassphrase: string
|
|
109
|
-
/** The new rule to install.
|
|
110
|
-
rule:
|
|
111
|
+
/** The new rule to install. */
|
|
112
|
+
rule: ContextRuleDraft
|
|
111
113
|
/** Per-rule install nonce; 1 for a fresh install. */
|
|
112
114
|
installNonce: number
|
|
113
115
|
/** Already-encoded (base64) canonical ScVal of the predicate. */
|
|
114
116
|
encodedPredicate: string
|
|
115
117
|
/** Hex sha256 of the canonical predicate XDR bytes. */
|
|
116
118
|
predicateHash: string
|
|
117
|
-
/** Per-policy oracle overrides. */
|
|
118
|
-
oracleParams?: {
|
|
119
|
-
maxStalenessSeconds?: number
|
|
120
|
-
maxDeviationBps?: number
|
|
121
|
-
maxCrossFeedDeviationBps?: number
|
|
122
|
-
}
|
|
123
119
|
/** Grammar version override; defaults to 1. */
|
|
124
120
|
grammarVersion?: number
|
|
125
121
|
/** Base fee in stroops; defaults to BASE_FEE (100). */
|
|
@@ -130,36 +126,6 @@ export interface BuildInstallPolicyArgs {
|
|
|
130
126
|
authValidUntilLedgers?: number
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
export type BuildInstallPolicyRuleDraft = {
|
|
134
|
-
contextRuleType:
|
|
135
|
-
| { kind: 'default' }
|
|
136
|
-
| { kind: 'call_contract'; contract: string }
|
|
137
|
-
| { kind: 'create_contract'; wasmHash: string }
|
|
138
|
-
name: string
|
|
139
|
-
validUntilLedger: number | null
|
|
140
|
-
signers: BuildInstallPolicySignerDraft[]
|
|
141
|
-
policies: BuildInstallPolicyPolicyRef[]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export type BuildInstallPolicySignerDraft =
|
|
145
|
-
| { kind: 'delegated'; address: string }
|
|
146
|
-
| { kind: 'external'; verifier: string; keyBytes: string }
|
|
147
|
-
|
|
148
|
-
export type BuildInstallPolicyPolicyRef =
|
|
149
|
-
| {
|
|
150
|
-
kind: 'interpreter'
|
|
151
|
-
interpreterAddress: string
|
|
152
|
-
predicateBlobBase64: string
|
|
153
|
-
}
|
|
154
|
-
| {
|
|
155
|
-
kind: 'oz_builtin'
|
|
156
|
-
instanceAddress: string
|
|
157
|
-
primitive: {
|
|
158
|
-
primitive: 'spending_limit' | 'simple_threshold' | 'weighted_threshold'
|
|
159
|
-
params: Record<string, unknown>
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
129
|
/** Human-readable description of the install call, decoded FROM the built
|
|
164
130
|
* XDR (not from the input args). The XDR is the source of truth: a
|
|
165
131
|
* human approving a review card needs the description to mirror the bytes
|
|
@@ -193,20 +159,13 @@ export interface InstallCallDescribes {
|
|
|
193
159
|
* sha256 of the predicate blob actually embedded in the XDR - so a
|
|
194
160
|
* mismatch between the wire bytes and the review card is detectable
|
|
195
161
|
* by reading `describes`. */
|
|
196
|
-
policies: Array<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
| {
|
|
205
|
-
kind: 'oz_builtin'
|
|
206
|
-
address: string
|
|
207
|
-
primitive: 'spending_limit' | 'simple_threshold' | 'weighted_threshold'
|
|
208
|
-
}
|
|
209
|
-
>
|
|
162
|
+
policies: Array<{
|
|
163
|
+
kind: 'interpreter'
|
|
164
|
+
address: string
|
|
165
|
+
installNonce: number
|
|
166
|
+
predicateHash: string
|
|
167
|
+
predicateSha256OfEmbeddedBytes: string
|
|
168
|
+
}>
|
|
210
169
|
/** The install nonce, decoded from the interpreter policy's
|
|
211
170
|
* `install_nonce` field. Echoed at the top level for reviewer convenience;
|
|
212
171
|
* the per-policy entry is the source of truth. */
|
|
@@ -261,102 +220,30 @@ export async function buildInstallPolicyXdr(
|
|
|
261
220
|
name: args.rule.name,
|
|
262
221
|
validUntilLedger: args.rule.validUntilLedger,
|
|
263
222
|
signers: args.rule.signers,
|
|
264
|
-
policies: args.rule.policies
|
|
223
|
+
policies: args.rule.policies,
|
|
265
224
|
},
|
|
266
225
|
{
|
|
267
226
|
signers: args.rule.signers,
|
|
268
|
-
policies: args.rule.policies
|
|
227
|
+
policies: args.rule.policies,
|
|
269
228
|
installNonce: args.installNonce,
|
|
270
229
|
encodedPredicate: args.encodedPredicate,
|
|
271
230
|
predicateHash: args.predicateHash,
|
|
272
|
-
...(args.oracleParams ? { oracleParams: args.oracleParams } : {}),
|
|
273
231
|
...(args.grammarVersion !== undefined ? { grammarVersion: args.grammarVersion } : {}),
|
|
274
232
|
}
|
|
275
233
|
)
|
|
276
234
|
|
|
277
|
-
// 2.
|
|
278
|
-
// bare host call. The recording pass assigns the smart-account auth nonce
|
|
279
|
-
// and root invocation needed to construct OZ's AuthPayload.
|
|
280
|
-
const source = await args.rpc.getAccount(args.sourceAccount)
|
|
281
|
-
const hostFunction = xdr.HostFunction.hostFunctionTypeInvokeContract(
|
|
282
|
-
new xdr.InvokeContractArgs({
|
|
283
|
-
contractAddress: new Address(args.smartAccount).toScAddress(),
|
|
284
|
-
functionName: 'add_context_rule',
|
|
285
|
-
args: [...callArgs],
|
|
286
|
-
})
|
|
287
|
-
)
|
|
288
|
-
const makeOperation = (auth: xdr.SorobanAuthorizationEntry[] = []) =>
|
|
289
|
-
Operation.invokeHostFunction({ func: hostFunction, auth })
|
|
290
|
-
const baseFee = args.baseFee !== undefined ? String(args.baseFee) : BASE_FEE
|
|
291
|
-
const buildTx = (op: xdr.Operation) =>
|
|
292
|
-
buildUnsignedTx({
|
|
293
|
-
sourceAccount: args.sourceAccount,
|
|
294
|
-
sequence: source.sequenceNumber(),
|
|
295
|
-
fee: baseFee,
|
|
296
|
-
networkPassphrase: args.networkPassphrase,
|
|
297
|
-
op,
|
|
298
|
-
})
|
|
299
|
-
const recordingTx = buildTx(makeOperation())
|
|
300
|
-
|
|
301
|
-
// 3. Recording simulation: capture the smart account's nonce and invocation
|
|
302
|
-
// tree. Nothing is signed here.
|
|
303
|
-
const recorded = await args.rpc.simulateTransaction(recordingTx)
|
|
304
|
-
if (rpc.Api.isSimulationError(recorded)) {
|
|
305
|
-
// Short, stable reason. The full `simulateTransaction` error (which
|
|
306
|
-
// carries host + URL detail) stays in the SDK's own logs - never
|
|
307
|
-
// reflected back into a user-facing message where it would
|
|
308
|
-
// reconnoitre the RPC.
|
|
309
|
-
throw new Error('install_policy: simulateTransaction failed')
|
|
310
|
-
}
|
|
311
|
-
const original = (recorded.result?.auth ?? []).find(
|
|
312
|
-
(entry) =>
|
|
313
|
-
entry.credentials().switch().name === 'sorobanCredentialsAddress' &&
|
|
314
|
-
Address.fromScAddress(entry.credentials().address().address()).toString() ===
|
|
315
|
-
args.smartAccount
|
|
316
|
-
)
|
|
317
|
-
if (!original) {
|
|
318
|
-
throw new Error(
|
|
319
|
-
`install_policy: no Soroban auth entry for smart account ${args.smartAccount}; this call does not route through the smart account`
|
|
320
|
-
)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// 4. `add_context_rule` is authorised by the deploy-time admin rule (rule 0).
|
|
235
|
+
// 2. `add_context_rule` is authorised by the deploy-time admin rule (rule 0).
|
|
324
236
|
// The delegated signer uses source-account credentials, so its signature
|
|
325
237
|
// bytes stay empty and the ordinary transaction-envelope signature covers
|
|
326
238
|
// the call when the consumer signs it.
|
|
327
|
-
const validUntilLedger =
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
signaturePayload(
|
|
333
|
-
args.networkPassphrase,
|
|
334
|
-
original.credentials().address().nonce(),
|
|
335
|
-
validUntilLedger,
|
|
336
|
-
original.rootInvocation()
|
|
337
|
-
),
|
|
338
|
-
contextRuleIds
|
|
239
|
+
const { finalTx, original, validUntilLedger } = await buildAuthorisedSmartAccountTx(
|
|
240
|
+
args,
|
|
241
|
+
'add_context_rule',
|
|
242
|
+
[...callArgs],
|
|
243
|
+
'install_policy'
|
|
339
244
|
)
|
|
340
|
-
const authEntries = [
|
|
341
|
-
accountEntry(
|
|
342
|
-
original,
|
|
343
|
-
validUntilLedger,
|
|
344
|
-
authPayload([args.sourceAccount], contextRuleIds, () => Buffer.alloc(0))
|
|
345
|
-
),
|
|
346
|
-
...contextRuleIds.map(() => delegatedSignerEntry(args.smartAccount, digest)),
|
|
347
|
-
]
|
|
348
245
|
|
|
349
|
-
//
|
|
350
|
-
// existing auth during assembly and adds the simulated Soroban footprint +
|
|
351
|
-
// resource fee, yielding a complete unsigned envelope.
|
|
352
|
-
const txWithAuth = buildTx(makeOperation(authEntries))
|
|
353
|
-
const enforcing = await args.rpc.simulateTransaction(txWithAuth)
|
|
354
|
-
if (rpc.Api.isSimulationError(enforcing)) {
|
|
355
|
-
throw new Error('install_policy: auth simulateTransaction failed')
|
|
356
|
-
}
|
|
357
|
-
const finalTx = rpc.assembleTransaction(txWithAuth, enforcing).build()
|
|
358
|
-
|
|
359
|
-
// 6. Decode the structured description FROM the final assembled transaction.
|
|
246
|
+
// 3. Decode the structured description FROM the final assembled transaction.
|
|
360
247
|
// The human approval binds to the exact bytes the wallet will sign.
|
|
361
248
|
const describes = decodeInstallCallDescribes(finalTx, args.installNonce)
|
|
362
249
|
|
|
@@ -392,12 +279,75 @@ export async function buildRevokePolicyXdr(args: {
|
|
|
392
279
|
baseFee?: number
|
|
393
280
|
authValidUntilLedgers?: number
|
|
394
281
|
}): Promise<BuildRevokePolicyResult> {
|
|
282
|
+
// Removal is master-only, so the deploy-time admin rule authorises it. The
|
|
283
|
+
// recorded rootInvocation still includes remove_context_rule(ruleId), binding
|
|
284
|
+
// the auth payload to the exact rule being removed. As with install,
|
|
285
|
+
// source-account credentials carry the delegated signer entry and the
|
|
286
|
+
// consumer supplies only the ordinary envelope signature.
|
|
287
|
+
const { finalTx, original, validUntilLedger } = await buildAuthorisedSmartAccountTx(
|
|
288
|
+
args,
|
|
289
|
+
'remove_context_rule',
|
|
290
|
+
[xdr.ScVal.scvU32(args.ruleId)],
|
|
291
|
+
'revoke_policy'
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
unsignedXdr: finalTx.toEnvelope().toXDR().toString('base64'),
|
|
296
|
+
smartAccount: args.smartAccount,
|
|
297
|
+
sourceAccount: args.sourceAccount,
|
|
298
|
+
call: { contract: args.smartAccount, fn: 'remove_context_rule', ruleId: args.ruleId },
|
|
299
|
+
authNonce: original.credentials().address().nonce().toString(),
|
|
300
|
+
authValidUntilLedger: validUntilLedger,
|
|
301
|
+
rootInvocationXdr: original.rootInvocation().toXDR().toString('base64'),
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export interface BuildRevokePolicyResult {
|
|
306
|
+
unsignedXdr: string
|
|
307
|
+
smartAccount: string
|
|
308
|
+
sourceAccount: string
|
|
309
|
+
call: { contract: string; fn: 'remove_context_rule'; ruleId: number }
|
|
310
|
+
authNonce: string
|
|
311
|
+
authValidUntilLedger: number
|
|
312
|
+
rootInvocationXdr: string
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** ~25 minutes at 5s/ledger. */
|
|
316
|
+
const DEFAULT_AUTH_VALID_UNTIL_LEDGERS = 300
|
|
317
|
+
|
|
318
|
+
// ---- internals ----
|
|
319
|
+
|
|
320
|
+
/** Record a bare call to the smart account, attach the deploy-time admin rule's
|
|
321
|
+
* auth entries, and re-simulate to assemble the footprint.
|
|
322
|
+
*
|
|
323
|
+
* Install and revoke differ only in the call they wrap, so they share this
|
|
324
|
+
* spine: the recording pass supplies the auth nonce and root invocation OZ's
|
|
325
|
+
* AuthPayload binds to, and the second simulation adds the Soroban footprint +
|
|
326
|
+
* resource fee. Nothing here is signed. `errorPrefix` names the calling tool in
|
|
327
|
+
* the fail-closed messages so a caller can still tell which call failed. */
|
|
328
|
+
async function buildAuthorisedSmartAccountTx(
|
|
329
|
+
args: {
|
|
330
|
+
smartAccount: string
|
|
331
|
+
sourceAccount: string
|
|
332
|
+
networkPassphrase: string
|
|
333
|
+
rpc: InstallRpcClient
|
|
334
|
+
baseFee?: number
|
|
335
|
+
authValidUntilLedgers?: number
|
|
336
|
+
},
|
|
337
|
+
functionName: string,
|
|
338
|
+
callArgs: xdr.ScVal[],
|
|
339
|
+
errorPrefix: string
|
|
340
|
+
): Promise<{
|
|
341
|
+
finalTx: Transaction
|
|
342
|
+
original: xdr.SorobanAuthorizationEntry
|
|
343
|
+
validUntilLedger: number
|
|
344
|
+
}> {
|
|
395
345
|
const source = await args.rpc.getAccount(args.sourceAccount)
|
|
396
346
|
const hostFunction = xdr.HostFunction.hostFunctionTypeInvokeContract(
|
|
397
347
|
new xdr.InvokeContractArgs({
|
|
398
348
|
contractAddress: new Address(args.smartAccount).toScAddress(),
|
|
399
|
-
functionName
|
|
400
|
-
args:
|
|
349
|
+
functionName,
|
|
350
|
+
args: callArgs,
|
|
401
351
|
})
|
|
402
352
|
)
|
|
403
353
|
const makeOperation = (auth: xdr.SorobanAuthorizationEntry[] = []) =>
|
|
@@ -418,7 +368,7 @@ export async function buildRevokePolicyXdr(args: {
|
|
|
418
368
|
// carries host + URL detail) stays in the SDK's own logs - never
|
|
419
369
|
// reflected back into a user-facing message where it would
|
|
420
370
|
// reconnoitre the RPC.
|
|
421
|
-
throw new Error(
|
|
371
|
+
throw new Error(`${errorPrefix}: simulateTransaction failed`)
|
|
422
372
|
}
|
|
423
373
|
const original = (recorded.result?.auth ?? []).find(
|
|
424
374
|
(entry) =>
|
|
@@ -428,15 +378,10 @@ export async function buildRevokePolicyXdr(args: {
|
|
|
428
378
|
)
|
|
429
379
|
if (!original) {
|
|
430
380
|
throw new Error(
|
|
431
|
-
|
|
381
|
+
`${errorPrefix}: no Soroban auth entry for smart account ${args.smartAccount}; this call does not route through the smart account`
|
|
432
382
|
)
|
|
433
383
|
}
|
|
434
384
|
|
|
435
|
-
// Removal is master-only, so the deploy-time admin rule authorises it. The
|
|
436
|
-
// recorded rootInvocation still includes remove_context_rule(ruleId), binding
|
|
437
|
-
// the auth payload to the exact rule being removed. As with install,
|
|
438
|
-
// source-account credentials carry the delegated signer entry and the
|
|
439
|
-
// consumer supplies only the ordinary envelope signature.
|
|
440
385
|
const validUntilLedger =
|
|
441
386
|
(await args.rpc.getLatestLedger()).sequence +
|
|
442
387
|
(args.authValidUntilLedgers ?? DEFAULT_AUTH_VALID_UNTIL_LEDGERS)
|
|
@@ -461,52 +406,12 @@ export async function buildRevokePolicyXdr(args: {
|
|
|
461
406
|
const txWithAuth = buildTx(makeOperation(authEntries))
|
|
462
407
|
const enforcing = await args.rpc.simulateTransaction(txWithAuth)
|
|
463
408
|
if (rpc.Api.isSimulationError(enforcing)) {
|
|
464
|
-
throw new Error(
|
|
465
|
-
}
|
|
466
|
-
const finalTx = rpc.assembleTransaction(txWithAuth, enforcing).build()
|
|
467
|
-
|
|
468
|
-
return {
|
|
469
|
-
unsignedXdr: finalTx.toEnvelope().toXDR().toString('base64'),
|
|
470
|
-
smartAccount: args.smartAccount,
|
|
471
|
-
sourceAccount: args.sourceAccount,
|
|
472
|
-
call: { contract: args.smartAccount, fn: 'remove_context_rule', ruleId: args.ruleId },
|
|
473
|
-
authNonce: original.credentials().address().nonce().toString(),
|
|
474
|
-
authValidUntilLedger: validUntilLedger,
|
|
475
|
-
rootInvocationXdr: original.rootInvocation().toXDR().toString('base64'),
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
export interface BuildRevokePolicyResult {
|
|
480
|
-
unsignedXdr: string
|
|
481
|
-
smartAccount: string
|
|
482
|
-
sourceAccount: string
|
|
483
|
-
call: { contract: string; fn: 'remove_context_rule'; ruleId: number }
|
|
484
|
-
authNonce: string
|
|
485
|
-
authValidUntilLedger: number
|
|
486
|
-
rootInvocationXdr: string
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/** ~25 minutes at 5s/ledger. */
|
|
490
|
-
const DEFAULT_AUTH_VALID_UNTIL_LEDGERS = 300
|
|
491
|
-
|
|
492
|
-
// ---- internals ----
|
|
493
|
-
|
|
494
|
-
/** Adapter: turn the install-policy wire `PolicyRef` shape into the core
|
|
495
|
-
* `PolicyRef` shape `buildAddContextRuleArgs` expects. Keeps the wire
|
|
496
|
-
* schema hand-rolled + flat (the strict union would need a recursive
|
|
497
|
-
* schema) while delegating to the proven encoder for the actual bytes. */
|
|
498
|
-
function adaptPolicyRef(p: BuildInstallPolicyPolicyRef) {
|
|
499
|
-
if (p.kind === 'interpreter') {
|
|
500
|
-
return {
|
|
501
|
-
kind: 'interpreter' as const,
|
|
502
|
-
interpreterAddress: p.interpreterAddress,
|
|
503
|
-
predicateBlobBase64: p.predicateBlobBase64,
|
|
504
|
-
}
|
|
409
|
+
throw new Error(`${errorPrefix}: auth simulateTransaction failed`)
|
|
505
410
|
}
|
|
506
411
|
return {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
412
|
+
finalTx: rpc.assembleTransaction(txWithAuth, enforcing).build(),
|
|
413
|
+
original,
|
|
414
|
+
validUntilLedger,
|
|
510
415
|
}
|
|
511
416
|
}
|
|
512
417
|
|
|
@@ -580,14 +485,13 @@ function decodeInstallCallDescribes(
|
|
|
580
485
|
`install_policy: built op has ${scvArgs.length} args, expected 5 (context_type, name, valid_until, signers, policies)`
|
|
581
486
|
)
|
|
582
487
|
}
|
|
583
|
-
const contextType = scvArgs[0]
|
|
584
488
|
const nameScv = scvArgs[1]
|
|
585
489
|
const validUntilScv = scvArgs[2]
|
|
586
490
|
const signersScv = scvArgs[3]
|
|
587
491
|
const policiesScv = scvArgs[4]
|
|
588
492
|
// The length check above pins these as defined; the local references
|
|
589
493
|
// satisfy noUncheckedIndexedAccess on the accessors below.
|
|
590
|
-
if (!nameScv || !validUntilScv || !signersScv || !policiesScv
|
|
494
|
+
if (!nameScv || !validUntilScv || !signersScv || !policiesScv) {
|
|
591
495
|
throw new Error('install_policy: built op args include an undefined slot despite length check')
|
|
592
496
|
}
|
|
593
497
|
|
|
@@ -672,7 +576,6 @@ function decodeInstallCallDescribes(
|
|
|
672
576
|
fields.set(fk.sym().toString(), inner.val())
|
|
673
577
|
}
|
|
674
578
|
// Interpreter policy fields carry grammar_version/install_nonce/predicate.
|
|
675
|
-
// OZ primitives carry spending_limit/period_ledgers/threshold/signers.
|
|
676
579
|
if (fields.has('predicate') || fields.has('grammar_version') || fields.has('install_nonce')) {
|
|
677
580
|
const installNonceScv = fields.get('install_nonce')
|
|
678
581
|
if (installNonceScv?.switch().name !== 'scvU32') {
|
|
@@ -706,21 +609,6 @@ function decodeInstallCallDescribes(
|
|
|
706
609
|
observedInstallNonce = installNonce
|
|
707
610
|
continue
|
|
708
611
|
}
|
|
709
|
-
// OZ built-in primitive. Distinguish by the parameter shape we
|
|
710
|
-
// emitted; matching one of the three primitives exactly pins the
|
|
711
|
-
// kind we built.
|
|
712
|
-
if (fields.has('spending_limit') && fields.has('period_ledgers')) {
|
|
713
|
-
policies.push({ kind: 'oz_builtin', address, primitive: 'spending_limit' })
|
|
714
|
-
continue
|
|
715
|
-
}
|
|
716
|
-
if (fields.has('threshold') && fields.has('signer_weights')) {
|
|
717
|
-
policies.push({ kind: 'oz_builtin', address, primitive: 'weighted_threshold' })
|
|
718
|
-
continue
|
|
719
|
-
}
|
|
720
|
-
if (fields.has('threshold')) {
|
|
721
|
-
policies.push({ kind: 'oz_builtin', address, primitive: 'simple_threshold' })
|
|
722
|
-
continue
|
|
723
|
-
}
|
|
724
612
|
throw new Error(
|
|
725
613
|
`install_policy: policies[${address}] value has an unknown field set; the encoder may have drifted`
|
|
726
614
|
)
|
|
@@ -752,12 +640,3 @@ function decodeInstallCallDescribes(
|
|
|
752
640
|
installNonce,
|
|
753
641
|
}
|
|
754
642
|
}
|
|
755
|
-
|
|
756
|
-
/** Re-export so the run-layer does not need to import from
|
|
757
|
-
* build-add-context-rule.ts (keeps the install/ -> install/ dependency
|
|
758
|
-
* direction intact). */
|
|
759
|
-
export { Contract, DEFAULT_GRAMMAR_VERSION }
|
|
760
|
-
|
|
761
|
-
// Local re-import to avoid pulling the class from the SDK module path
|
|
762
|
-
// at the top of the file (avoids the unused-import lint).
|
|
763
|
-
import { Account } from '@stellar/stellar-sdk'
|