@crediolabs/policy-synth 0.3.1 → 0.5.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.
Files changed (100) hide show
  1. package/dist/adapters/interpreter/adapter.d.ts +2 -2
  2. package/dist/adapters/interpreter/adapter.js +11 -3
  3. package/dist/errors.d.ts +6 -1
  4. package/dist/install/authority-overlap.d.ts +101 -0
  5. package/dist/install/authority-overlap.js +239 -0
  6. package/dist/install/build-add-context-rule.d.ts +1 -1
  7. package/dist/install/index.d.ts +1 -0
  8. package/dist/install/index.js +4 -0
  9. package/dist/install/read-account-rules.d.ts +79 -0
  10. package/dist/install/read-account-rules.js +241 -0
  11. package/dist/predicate/decode.js +22 -1
  12. package/dist/predicate/encode.js +52 -5
  13. package/dist/predicate/from-json.js +14 -1
  14. package/dist/record/index.d.ts +10 -0
  15. package/dist/record/index.js +32 -1
  16. package/dist/record/rpc.d.ts +4 -0
  17. package/dist/record/rpc.js +4 -1
  18. package/dist/registry/identify.d.ts +10 -1
  19. package/dist/registry/identify.js +4 -1
  20. package/dist/registry/on-chain-spec.d.ts +37 -0
  21. package/dist/registry/on-chain-spec.js +152 -0
  22. package/dist/review-card/builder.js +40 -0
  23. package/dist/review-card/cross-check.js +34 -0
  24. package/dist/review-card/render-leaf.d.ts +1 -1
  25. package/dist/review-card/render-leaf.js +7 -0
  26. package/dist/run/index.d.ts +25 -4
  27. package/dist/run/index.js +108 -4
  28. package/dist/run/schemas.d.ts +350 -6
  29. package/dist/run/schemas.js +95 -6
  30. package/dist/simulate/deny-cases.js +11 -0
  31. package/dist/simulate/evaluate.js +86 -5
  32. package/dist/synth/declare.d.ts +43 -0
  33. package/dist/synth/declare.js +127 -0
  34. package/dist/synth/index.d.ts +1 -0
  35. package/dist/synth/index.js +1 -0
  36. package/dist/synth/synthesize-from-recording.js +1 -1
  37. package/dist/types.d.ts +21 -1
  38. package/dist/types.js +1 -1
  39. package/dist-cjs/adapters/interpreter/adapter.d.ts +2 -2
  40. package/dist-cjs/adapters/interpreter/adapter.js +11 -3
  41. package/dist-cjs/errors.d.ts +6 -1
  42. package/dist-cjs/install/authority-overlap.d.ts +101 -0
  43. package/dist-cjs/install/authority-overlap.js +248 -0
  44. package/dist-cjs/install/build-add-context-rule.d.ts +1 -1
  45. package/dist-cjs/install/index.d.ts +1 -0
  46. package/dist-cjs/install/index.js +13 -2
  47. package/dist-cjs/install/read-account-rules.d.ts +79 -0
  48. package/dist-cjs/install/read-account-rules.js +252 -0
  49. package/dist-cjs/predicate/decode.js +22 -1
  50. package/dist-cjs/predicate/encode.js +52 -5
  51. package/dist-cjs/predicate/from-json.js +14 -1
  52. package/dist-cjs/record/index.d.ts +10 -0
  53. package/dist-cjs/record/index.js +31 -0
  54. package/dist-cjs/record/rpc.d.ts +4 -0
  55. package/dist-cjs/record/rpc.js +7 -3
  56. package/dist-cjs/registry/identify.d.ts +10 -1
  57. package/dist-cjs/registry/identify.js +4 -0
  58. package/dist-cjs/registry/on-chain-spec.d.ts +37 -0
  59. package/dist-cjs/registry/on-chain-spec.js +159 -0
  60. package/dist-cjs/review-card/builder.js +40 -0
  61. package/dist-cjs/review-card/cross-check.js +34 -0
  62. package/dist-cjs/review-card/render-leaf.d.ts +1 -1
  63. package/dist-cjs/review-card/render-leaf.js +7 -0
  64. package/dist-cjs/run/index.d.ts +25 -4
  65. package/dist-cjs/run/index.js +108 -2
  66. package/dist-cjs/run/schemas.d.ts +350 -6
  67. package/dist-cjs/run/schemas.js +96 -7
  68. package/dist-cjs/simulate/deny-cases.js +11 -0
  69. package/dist-cjs/simulate/evaluate.js +86 -5
  70. package/dist-cjs/synth/declare.d.ts +43 -0
  71. package/dist-cjs/synth/declare.js +130 -0
  72. package/dist-cjs/synth/index.d.ts +1 -0
  73. package/dist-cjs/synth/index.js +3 -1
  74. package/dist-cjs/synth/synthesize-from-recording.js +1 -1
  75. package/dist-cjs/types.d.ts +21 -1
  76. package/dist-cjs/types.js +1 -1
  77. package/package.json +1 -1
  78. package/src/adapters/interpreter/adapter.ts +13 -5
  79. package/src/errors.ts +5 -0
  80. package/src/install/authority-overlap.ts +323 -0
  81. package/src/install/index.ts +20 -0
  82. package/src/install/read-account-rules.ts +313 -0
  83. package/src/predicate/decode.ts +22 -1
  84. package/src/predicate/encode.ts +55 -5
  85. package/src/predicate/from-json.ts +14 -1
  86. package/src/record/index.ts +59 -2
  87. package/src/record/rpc.ts +4 -1
  88. package/src/registry/identify.ts +4 -1
  89. package/src/registry/on-chain-spec.ts +168 -0
  90. package/src/review-card/builder.ts +45 -2
  91. package/src/review-card/cross-check.ts +35 -1
  92. package/src/review-card/render-leaf.ts +8 -1
  93. package/src/run/index.ts +125 -2
  94. package/src/run/schemas.ts +100 -6
  95. package/src/simulate/deny-cases.ts +12 -1
  96. package/src/simulate/evaluate.ts +101 -9
  97. package/src/synth/declare.ts +206 -0
  98. package/src/synth/index.ts +5 -0
  99. package/src/synth/synthesize-from-recording.ts +1 -1
  100. package/src/types.ts +16 -1
@@ -1,14 +1,15 @@
1
1
  import { type ErrorCode, type PredicateNode, type ProposedPolicy, type RecordedTransaction, type ToolError, type ToolResponse } from '../index.ts';
2
+ import { type AuthorityOverlap } from '../install/authority-overlap.ts';
2
3
  import { type BuildInstallPolicyResult, type BuildRevokePolicyResult } from '../install/build-install-policy.ts';
3
4
  import { getInterpreterInfo } from '../install/get-interpreter-info.ts';
4
5
  import { type RecordTransactionInput, type SimulatePolicyInput, type SynthesizePolicyInput, type VerifyPolicyInput } from './schemas.ts';
5
- export type { GetInterpreterInfoInput, InstallPolicyInput, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
6
- export { ComposeUserResponsesSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
6
+ export type { DeclarePolicyInput, GetInterpreterInfoInput, InstallPolicyInput, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
7
+ export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
7
8
  export type RunRecordTransactionInput = RecordTransactionInput;
8
9
  export type RunSynthesizePolicyInput = SynthesizePolicyInput;
9
10
  export type RunSimulatePolicyInput = SimulatePolicyInput;
10
11
  export type RunVerifyPolicyInput = VerifyPolicyInput;
11
- type RunToolName = 'record_transaction' | 'synthesize_policy' | 'simulate_policy' | 'verify_policy' | 'install_policy' | 'revoke_policy' | 'get_interpreter_info';
12
+ type RunToolName = 'record_transaction' | 'synthesize_policy' | 'declare_policy' | 'simulate_policy' | 'verify_policy' | 'install_policy' | 'revoke_policy' | 'get_interpreter_info';
12
13
  /** `record_transaction` body - wraps `recordTransaction`. The tool input
13
14
  * matches the core RecordInput minus the injected `fetcher` (the transport
14
15
  * layer does not own the RPC). Returns the core ToolResponse unchanged.
@@ -37,7 +38,9 @@ export declare function runSynthesizePolicy(raw: unknown): Promise<ToolResponse<
37
38
  predicateTree: PredicateNode | null;
38
39
  };
39
40
  }>;
40
- export declare function runInstallPolicy(raw: unknown): Promise<ToolResponse<BuildInstallPolicyResult>>;
41
+ export declare function runInstallPolicy(raw: unknown): Promise<ToolResponse<BuildInstallPolicyResult & {
42
+ authorityScan: AuthorityOverlap[] | null;
43
+ }>>;
41
44
  /** `revoke_policy` body - thin wrapper over `buildRevokePolicyXdr`.
42
45
  * Emits an unsigned XDR for `account.remove_context_rule(ruleId)`; the
43
46
  * smart account itself handles uninstalling each attached policy. Auth
@@ -63,6 +66,24 @@ export declare function runSimulatePolicy(raw: unknown): ToolResponse<{
63
66
  argCount: number;
64
67
  };
65
68
  }>;
69
+ /** `declare_policy` body - the DECLARATIVE front-end.
70
+ *
71
+ * `synthesize_policy` infers a predicate from a transaction that happened;
72
+ * this takes the constraint stated outright. No RPC, no decoding and no
73
+ * parseConfidence, so nothing here can be refused for a contract the registry
74
+ * does not recognise - which is most of the point of having it.
75
+ *
76
+ * The returned `warnings` are load-bearing, not decoration. An argument index
77
+ * the caller did not supply is DEFAULTED to the SEP-41 position, and a bound
78
+ * on the wrong argument constrains something the caller did not mean without
79
+ * ever announcing itself, so a caller that ignores warnings can install a
80
+ * predicate that reads correctly and binds nothing. */
81
+ export declare function runDeclarePolicy(raw: unknown): ToolResponse<{
82
+ predicate: PredicateNode;
83
+ encodedPredicate: string;
84
+ predicateHash: string;
85
+ warnings: string[];
86
+ }>;
66
87
  /** `verify_policy` body - the permit case plus a generated deny case per
67
88
  * dimension.
68
89
  *
@@ -18,20 +18,24 @@
18
18
  // No business logic. No retries. No session state. The same call shape can
19
19
  // drive the CLI (which calls into the same core directly without MCP).
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.RPC_URL_BY_NETWORK = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.NetworkSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.ComposeUserResponsesSchema = void 0;
21
+ exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.RPC_URL_BY_NETWORK = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.NetworkSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.DeclarePolicyInputSchema = exports.ComposeUserResponsesSchema = void 0;
22
22
  exports.runRecordTransaction = runRecordTransaction;
23
23
  exports.runSynthesizePolicy = runSynthesizePolicy;
24
24
  exports.runInstallPolicy = runInstallPolicy;
25
25
  exports.runRevokePolicy = runRevokePolicy;
26
26
  exports.runSimulatePolicy = runSimulatePolicy;
27
+ exports.runDeclarePolicy = runDeclarePolicy;
27
28
  exports.runVerifyPolicy = runVerifyPolicy;
28
29
  exports.runGetInterpreterInfo = runGetInterpreterInfo;
29
30
  exports.caughtError = caughtError;
30
31
  const node_crypto_1 = require("node:crypto");
31
32
  const stellar_sdk_1 = require("@stellar/stellar-sdk");
32
33
  const index_ts_1 = require("../index.js");
34
+ const authority_overlap_ts_1 = require("../install/authority-overlap.js");
33
35
  const build_install_policy_ts_1 = require("../install/build-install-policy.js");
34
36
  const get_interpreter_info_ts_1 = require("../install/get-interpreter-info.js");
37
+ const read_account_rules_ts_1 = require("../install/read-account-rules.js");
38
+ const decode_ts_1 = require("../predicate/decode.js");
35
39
  const index_ts_2 = require("../simulate/index.js");
36
40
  const schemas_ts_1 = require("./schemas.js");
37
41
  // Re-export the underlying Zod schemas so the MCP package (and any other
@@ -40,6 +44,7 @@ const schemas_ts_1 = require("./schemas.js");
40
44
  // truth - MCP tool shapes are derived from them.
41
45
  var schemas_ts_2 = require("./schemas.js");
42
46
  Object.defineProperty(exports, "ComposeUserResponsesSchema", { enumerable: true, get: function () { return schemas_ts_2.ComposeUserResponsesSchema; } });
47
+ Object.defineProperty(exports, "DeclarePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.DeclarePolicyInputSchema; } });
43
48
  Object.defineProperty(exports, "GetInterpreterInfoInputSchema", { enumerable: true, get: function () { return schemas_ts_2.GetInterpreterInfoInputSchema; } });
44
49
  Object.defineProperty(exports, "InstallPolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.InstallPolicyInputSchema; } });
45
50
  Object.defineProperty(exports, "InterpreterOptionsSchema", { enumerable: true, get: function () { return schemas_ts_2.InterpreterOptionsSchema; } });
@@ -65,6 +70,7 @@ Object.defineProperty(exports, "ToolErrorSchema", { enumerable: true, get: funct
65
70
  const TOOL_ERROR_CODE = {
66
71
  record_transaction: 'RECORDING_FAILED',
67
72
  synthesize_policy: 'SYNTHESIS_ERROR',
73
+ declare_policy: 'SYNTHESIS_ERROR',
68
74
  simulate_policy: 'SIMULATION_ERROR',
69
75
  verify_policy: 'VERIFICATION_FAILED',
70
76
  install_policy: 'INSTALL_BUILD_FAILED',
@@ -179,7 +185,32 @@ async function runInstallPolicy(raw) {
179
185
  rpc: rpcClient,
180
186
  ...(input.baseFee !== undefined ? { baseFee: input.baseFee } : {}),
181
187
  });
182
- return { ok: true, data: result };
188
+ // Cross-rule scan. The caller may supply `existingRules` (useful offline,
189
+ // and for testing); otherwise the account is READ, so the answer describes
190
+ // what is actually installed rather than what the caller happened to
191
+ // mention.
192
+ //
193
+ // `null` means NOT CHECKED and is returned whenever the scan cannot be
194
+ // trusted to be complete - the read failed, or it stopped before
195
+ // accounting for every live rule. An empty list would say "checked,
196
+ // nothing found", and a partial scan that reported `[]` would be claiming
197
+ // a safety it never established.
198
+ const observed = await resolveExistingRules(input, network, expectedInterpreter);
199
+ const authorityScan = observed === null
200
+ ? null
201
+ : (0, authority_overlap_ts_1.findAuthorityOverlaps)({
202
+ intended: {
203
+ // `add_context_rule` gets its id FROM the account, so there is
204
+ // no existing rule this install replaces. A sentinel no real id
205
+ // can equal keeps every observed rule in scope.
206
+ ruleId: -1,
207
+ contextType: input.rule.contextRuleType,
208
+ signers: input.rule.signers,
209
+ predicate: (0, decode_ts_1.decodePredicate)(encodedPredicate),
210
+ },
211
+ existing: observed,
212
+ });
213
+ return { ok: true, data: { ...result, authorityScan } };
183
214
  }
184
215
  catch (e) {
185
216
  return toolFailure('install_policy', e);
@@ -298,6 +329,45 @@ function runSimulatePolicy(raw) {
298
329
  return toolFailure('simulate_policy', e);
299
330
  }
300
331
  }
332
+ /** `declare_policy` body - the DECLARATIVE front-end.
333
+ *
334
+ * `synthesize_policy` infers a predicate from a transaction that happened;
335
+ * this takes the constraint stated outright. No RPC, no decoding and no
336
+ * parseConfidence, so nothing here can be refused for a contract the registry
337
+ * does not recognise - which is most of the point of having it.
338
+ *
339
+ * The returned `warnings` are load-bearing, not decoration. An argument index
340
+ * the caller did not supply is DEFAULTED to the SEP-41 position, and a bound
341
+ * on the wrong argument constrains something the caller did not mean without
342
+ * ever announcing itself, so a caller that ignores warnings can install a
343
+ * predicate that reads correctly and binds nothing. */
344
+ function runDeclarePolicy(raw) {
345
+ const parsed = schemas_ts_1.DeclarePolicyInputSchema.safeParse(raw);
346
+ if (!parsed.success) {
347
+ return { ok: false, error: validationError('declare_policy', parsed.error.issues) };
348
+ }
349
+ try {
350
+ // Rebuilt field-by-field rather than passed through: the schema's
351
+ // optionals are `T | undefined` and `PolicyDeclaration`'s are absent-or-T,
352
+ // which `exactOptionalPropertyTypes` treats as different.
353
+ const d = parsed.data;
354
+ const { predicate, warnings } = (0, index_ts_1.declarePredicate)({
355
+ fn: d.fn,
356
+ ...(d.contract !== undefined ? { contract: d.contract } : {}),
357
+ ...(d.maxAmount !== undefined ? { maxAmount: d.maxAmount } : {}),
358
+ ...(d.amountArgIndex !== undefined ? { amountArgIndex: d.amountArgIndex } : {}),
359
+ ...(d.recipients !== undefined ? { recipients: d.recipients } : {}),
360
+ ...(d.recipientArgIndex !== undefined ? { recipientArgIndex: d.recipientArgIndex } : {}),
361
+ ...(d.allowZeroCap !== undefined ? { allowZeroCap: d.allowZeroCap } : {}),
362
+ ...(d.minOutputRatio !== undefined ? { minOutputRatio: d.minOutputRatio } : {}),
363
+ });
364
+ const { encodedPredicate, predicateHash } = (0, index_ts_1.encodePredicate)(predicate);
365
+ return { ok: true, data: { predicate, encodedPredicate, predicateHash, warnings } };
366
+ }
367
+ catch (e) {
368
+ return toolFailure('declare_policy', e);
369
+ }
370
+ }
301
371
  /** `verify_policy` body - the permit case plus a generated deny case per
302
372
  * dimension.
303
373
  *
@@ -385,6 +455,42 @@ async function runGetInterpreterInfo(raw) {
385
455
  * network, falling back to the pinned RPC for the network. The caller
386
456
  * has already been gated against the pinned URL elsewhere, so the
387
457
  * fallback here only ever picks from a finite, audited pair. */
458
+ /** The account's other context rules, or `null` when they could not be
459
+ * established completely.
460
+ *
461
+ * Caller-supplied `existingRules` win: they let the scan run offline, and a
462
+ * caller who passes them has said what to compare against. Otherwise the
463
+ * account is read over RPC.
464
+ *
465
+ * Every failure path returns `null` rather than a short list. A read that
466
+ * threw, or one that stopped before accounting for every live rule, has not
467
+ * ruled anything out - and reporting `[]` there would turn "we could not
468
+ * check" into "there is nothing to worry about". */
469
+ async function resolveExistingRules(input, network, interpreterAddress) {
470
+ if (input.existingRules !== undefined) {
471
+ // The schema types `predicate` loosely (it is the shared
472
+ // PredicateNodeSchema); the shape is already validated.
473
+ return input.existingRules;
474
+ }
475
+ try {
476
+ const url = input.rpcUrl ?? schemas_ts_1.RPC_URL_BY_NETWORK[network];
477
+ const server = new stellar_sdk_1.rpc.Server(url, { allowHttp: false });
478
+ const collected = await (0, read_account_rules_ts_1.collectObservedRules)({
479
+ reader: (0, read_account_rules_ts_1.accountRuleReaderFromServer)(server, schemas_ts_1.NETWORK_PASSPHRASES[network]),
480
+ smartAccount: input.smartAccount,
481
+ interpreterAddress,
482
+ });
483
+ if (collected.incomplete)
484
+ return null;
485
+ return collected.rules;
486
+ }
487
+ catch {
488
+ // The install itself is unaffected: the scan is advisory, so a failed
489
+ // read must not block a policy the user asked for. It just cannot be
490
+ // reported as a clean scan.
491
+ return null;
492
+ }
493
+ }
388
494
  function buildRpcClientFromInput(urlOverride, network) {
389
495
  const url = urlOverride ?? schemas_ts_1.RPC_URL_BY_NETWORK[network];
390
496
  const passphrase = schemas_ts_1.NETWORK_PASSPHRASES[network];
@@ -1494,25 +1494,123 @@ export declare const VerifyPolicyInputSchema: z.ZodObject<{
1494
1494
  predicate?: unknown;
1495
1495
  }>;
1496
1496
  export type VerifyPolicyInput = z.infer<typeof VerifyPolicyInputSchema>;
1497
+ /** A rule ALREADY on the account, as the caller observed it. Supplying these
1498
+ * turns on the cross-rule authority scan: a signer belonging to several rules
1499
+ * picks which one applies, so a predicate only constrains a key when the
1500
+ * policed rule is the only rule that key is on. */
1501
+ export declare const ObservedRuleSchema: z.ZodObject<{
1502
+ id: z.ZodNumber;
1503
+ contextType: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
1504
+ kind: z.ZodLiteral<"default">;
1505
+ }, "strip", z.ZodTypeAny, {
1506
+ kind: "default";
1507
+ }, {
1508
+ kind: "default";
1509
+ }>, z.ZodObject<{
1510
+ kind: z.ZodLiteral<"call_contract">;
1511
+ contract: z.ZodString;
1512
+ }, "strip", z.ZodTypeAny, {
1513
+ kind: "call_contract";
1514
+ contract: string;
1515
+ }, {
1516
+ kind: "call_contract";
1517
+ contract: string;
1518
+ }>, z.ZodObject<{
1519
+ kind: z.ZodLiteral<"create_contract">;
1520
+ wasmHash: z.ZodString;
1521
+ }, "strip", z.ZodTypeAny, {
1522
+ kind: "create_contract";
1523
+ wasmHash: string;
1524
+ }, {
1525
+ kind: "create_contract";
1526
+ wasmHash: string;
1527
+ }>]>;
1528
+ signers: z.ZodArray<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
1529
+ kind: z.ZodLiteral<"delegated">;
1530
+ address: z.ZodString;
1531
+ }, "strip", z.ZodTypeAny, {
1532
+ address: string;
1533
+ kind: "delegated";
1534
+ }, {
1535
+ address: string;
1536
+ kind: "delegated";
1537
+ }>, z.ZodObject<{
1538
+ kind: z.ZodLiteral<"external">;
1539
+ verifier: z.ZodString;
1540
+ keyBytes: z.ZodString;
1541
+ }, "strip", z.ZodTypeAny, {
1542
+ kind: "external";
1543
+ verifier: string;
1544
+ keyBytes: string;
1545
+ }, {
1546
+ kind: "external";
1547
+ verifier: string;
1548
+ keyBytes: string;
1549
+ }>]>, "many">;
1550
+ policyAddresses: z.ZodArray<z.ZodString, "many">;
1551
+ predicate: z.ZodOptional<z.ZodType<unknown, z.ZodTypeDef, unknown>>;
1552
+ }, "strip", z.ZodTypeAny, {
1553
+ signers: ({
1554
+ address: string;
1555
+ kind: "delegated";
1556
+ } | {
1557
+ kind: "external";
1558
+ verifier: string;
1559
+ keyBytes: string;
1560
+ })[];
1561
+ id: number;
1562
+ policyAddresses: string[];
1563
+ contextType: {
1564
+ kind: "default";
1565
+ } | {
1566
+ kind: "call_contract";
1567
+ contract: string;
1568
+ } | {
1569
+ kind: "create_contract";
1570
+ wasmHash: string;
1571
+ };
1572
+ predicate?: unknown;
1573
+ }, {
1574
+ signers: ({
1575
+ address: string;
1576
+ kind: "delegated";
1577
+ } | {
1578
+ kind: "external";
1579
+ verifier: string;
1580
+ keyBytes: string;
1581
+ })[];
1582
+ id: number;
1583
+ policyAddresses: string[];
1584
+ contextType: {
1585
+ kind: "default";
1586
+ } | {
1587
+ kind: "call_contract";
1588
+ contract: string;
1589
+ } | {
1590
+ kind: "create_contract";
1591
+ wasmHash: string;
1592
+ };
1593
+ predicate?: unknown;
1594
+ }>;
1497
1595
  /** Pinned interpreter address (testnet).
1498
1596
  * Single source for the MCP layer; do not embed elsewhere. */
1499
- export declare const PINNED_INTERPRETER_TESTNET_ADDRESS = "CCL336TCK2Y5OFNRCMN2M3HVPBCEX4PW5H6EQ5VW5NPMXOCP4ESB5XR4";
1500
- /** Pinned interpreter address (mainnet), redeployed 2026-08-22 from a reproducible build. The mainnet
1597
+ export declare const PINNED_INTERPRETER_TESTNET_ADDRESS = "CCBHVZ6HGGV7C4SNHCZ3S5665Z2WEMHTMBAEPO4XW6PKON464BEBANU5";
1598
+ /** Pinned interpreter address (mainnet), redeployed 2026-08-22 for grammar 4, from a reproducible build. The mainnet
1501
1599
  * interpreter IS the binary exercised on testnet - both instances were created
1502
1600
  * from the same uploaded wasm hash (see PINNED_INTERPRETER_WASM_SHA256), and
1503
- * both were read back with `grammar_version()` returning 3. The address differs
1601
+ * both were read back with `grammar_version()` returning 4. The address differs
1504
1602
  * because instance ids are network-scoped. UNAUDITED at the time of writing.
1505
1603
  *
1506
1604
  * These four constants move together or not at all. The grammar version and
1507
1605
  * wasm hash are single values covering BOTH networks, so re-pinning one network
1508
1606
  * alone would have the builder emit a version the other network refuses - with
1509
1607
  * a green test run, since `grammar-version-parity.test.ts` would then pass. */
1510
- export declare const PINNED_INTERPRETER_MAINNET_ADDRESS = "CBZXLSTQUITBFZHQH6XRXF3XIVRQR4RHRI64Q5WELS5KGY3ZKJPFWDPF";
1608
+ export declare const PINNED_INTERPRETER_MAINNET_ADDRESS = "CDN755TDYZM3ZQ5OXTJ6TIBUBWZV2KRI2BYJPBXD2MVWED4STT3VBN52";
1511
1609
  /** Pinned interpreter wasm sha256 (hex). */
1512
- export declare const PINNED_INTERPRETER_WASM_SHA256 = "a2b36e8ac5a61caf3757af26aa79e83f2995b451099f44772383806a55fe3414";
1610
+ export declare const PINNED_INTERPRETER_WASM_SHA256 = "b5ba1e35ccf20cd8c13c3a2c3098bf337033a92bcaf475d63c03ddc0cba0fcae";
1513
1611
  /** The grammar version the interpreter enforces (matches SELF_VERSION in
1514
1612
  * contracts/policy-interpreter/src/version.rs). */
1515
- export declare const PINNED_INTERPRETER_GRAMMAR_VERSION = 3;
1613
+ export declare const PINNED_INTERPRETER_GRAMMAR_VERSION = 4;
1516
1614
  /** Default Soroban RPC for the install / revoke / info tools. The recorder
1517
1615
  * keeps its own copy in record/rpc.ts because it hands back a fetcher rather
1518
1616
  * than a Server; the two are deliberately different surfaces, so this is
@@ -1533,7 +1631,165 @@ export declare const RPC_URL_BY_NETWORK: Record<Network, string>;
1533
1631
  * matching passphrase when the wallet signs (a mismatch yields invalid
1534
1632
  * hashes). */
1535
1633
  export declare const NETWORK_PASSPHRASES: Record<Network, string>;
1634
+ export declare const DeclarePolicyInputSchema: z.ZodObject<{
1635
+ fn: z.ZodString;
1636
+ contract: z.ZodOptional<z.ZodString>;
1637
+ /** Smallest unit, unsigned decimal STRING - an i128 is wider than
1638
+ * Number.MAX_SAFE_INTEGER, so a number here would silently round. */
1639
+ maxAmount: z.ZodOptional<z.ZodString>;
1640
+ amountArgIndex: z.ZodOptional<z.ZodNumber>;
1641
+ recipients: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1642
+ recipientArgIndex: z.ZodOptional<z.ZodNumber>;
1643
+ allowZeroCap: z.ZodOptional<z.ZodBoolean>;
1644
+ /** Minimum output as a ratio of the call's own input. num/den are decimal
1645
+ * STRINGS for the same reason maxAmount is: an i128 ratio does not
1646
+ * survive a JS number. */
1647
+ minOutputRatio: z.ZodOptional<z.ZodObject<{
1648
+ num: z.ZodString;
1649
+ den: z.ZodString;
1650
+ inputArgIndex: z.ZodNumber;
1651
+ outputArgIndex: z.ZodNumber;
1652
+ }, "strict", z.ZodTypeAny, {
1653
+ num: string;
1654
+ den: string;
1655
+ inputArgIndex: number;
1656
+ outputArgIndex: number;
1657
+ }, {
1658
+ num: string;
1659
+ den: string;
1660
+ inputArgIndex: number;
1661
+ outputArgIndex: number;
1662
+ }>>;
1663
+ }, "strict", z.ZodTypeAny, {
1664
+ fn: string;
1665
+ contract?: string | undefined;
1666
+ maxAmount?: string | undefined;
1667
+ amountArgIndex?: number | undefined;
1668
+ recipients?: string[] | undefined;
1669
+ recipientArgIndex?: number | undefined;
1670
+ allowZeroCap?: boolean | undefined;
1671
+ minOutputRatio?: {
1672
+ num: string;
1673
+ den: string;
1674
+ inputArgIndex: number;
1675
+ outputArgIndex: number;
1676
+ } | undefined;
1677
+ }, {
1678
+ fn: string;
1679
+ contract?: string | undefined;
1680
+ maxAmount?: string | undefined;
1681
+ amountArgIndex?: number | undefined;
1682
+ recipients?: string[] | undefined;
1683
+ recipientArgIndex?: number | undefined;
1684
+ allowZeroCap?: boolean | undefined;
1685
+ minOutputRatio?: {
1686
+ num: string;
1687
+ den: string;
1688
+ inputArgIndex: number;
1689
+ outputArgIndex: number;
1690
+ } | undefined;
1691
+ }>;
1692
+ export type DeclarePolicyInput = z.infer<typeof DeclarePolicyInputSchema>;
1536
1693
  export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
1694
+ /** Rules already on the account. Supplying them turns on the cross-rule
1695
+ * authority scan, which reports every existing rule a signer of this
1696
+ * install could name INSTEAD - including an unpoliced one, against which
1697
+ * the predicate never runs. Absent means the scan is skipped, and the
1698
+ * result says so rather than reporting "no overlaps found". */
1699
+ existingRules: z.ZodOptional<z.ZodArray<z.ZodObject<{
1700
+ id: z.ZodNumber;
1701
+ contextType: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
1702
+ kind: z.ZodLiteral<"default">;
1703
+ }, "strip", z.ZodTypeAny, {
1704
+ kind: "default";
1705
+ }, {
1706
+ kind: "default";
1707
+ }>, z.ZodObject<{
1708
+ kind: z.ZodLiteral<"call_contract">;
1709
+ contract: z.ZodString;
1710
+ }, "strip", z.ZodTypeAny, {
1711
+ kind: "call_contract";
1712
+ contract: string;
1713
+ }, {
1714
+ kind: "call_contract";
1715
+ contract: string;
1716
+ }>, z.ZodObject<{
1717
+ kind: z.ZodLiteral<"create_contract">;
1718
+ wasmHash: z.ZodString;
1719
+ }, "strip", z.ZodTypeAny, {
1720
+ kind: "create_contract";
1721
+ wasmHash: string;
1722
+ }, {
1723
+ kind: "create_contract";
1724
+ wasmHash: string;
1725
+ }>]>;
1726
+ signers: z.ZodArray<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
1727
+ kind: z.ZodLiteral<"delegated">;
1728
+ address: z.ZodString;
1729
+ }, "strip", z.ZodTypeAny, {
1730
+ address: string;
1731
+ kind: "delegated";
1732
+ }, {
1733
+ address: string;
1734
+ kind: "delegated";
1735
+ }>, z.ZodObject<{
1736
+ kind: z.ZodLiteral<"external">;
1737
+ verifier: z.ZodString;
1738
+ keyBytes: z.ZodString;
1739
+ }, "strip", z.ZodTypeAny, {
1740
+ kind: "external";
1741
+ verifier: string;
1742
+ keyBytes: string;
1743
+ }, {
1744
+ kind: "external";
1745
+ verifier: string;
1746
+ keyBytes: string;
1747
+ }>]>, "many">;
1748
+ policyAddresses: z.ZodArray<z.ZodString, "many">;
1749
+ predicate: z.ZodOptional<z.ZodType<unknown, z.ZodTypeDef, unknown>>;
1750
+ }, "strip", z.ZodTypeAny, {
1751
+ signers: ({
1752
+ address: string;
1753
+ kind: "delegated";
1754
+ } | {
1755
+ kind: "external";
1756
+ verifier: string;
1757
+ keyBytes: string;
1758
+ })[];
1759
+ id: number;
1760
+ policyAddresses: string[];
1761
+ contextType: {
1762
+ kind: "default";
1763
+ } | {
1764
+ kind: "call_contract";
1765
+ contract: string;
1766
+ } | {
1767
+ kind: "create_contract";
1768
+ wasmHash: string;
1769
+ };
1770
+ predicate?: unknown;
1771
+ }, {
1772
+ signers: ({
1773
+ address: string;
1774
+ kind: "delegated";
1775
+ } | {
1776
+ kind: "external";
1777
+ verifier: string;
1778
+ keyBytes: string;
1779
+ })[];
1780
+ id: number;
1781
+ policyAddresses: string[];
1782
+ contextType: {
1783
+ kind: "default";
1784
+ } | {
1785
+ kind: "call_contract";
1786
+ contract: string;
1787
+ } | {
1788
+ kind: "create_contract";
1789
+ wasmHash: string;
1790
+ };
1791
+ predicate?: unknown;
1792
+ }>, "many">>;
1537
1793
  /** The smart account contract address (C...) that will receive the rule. */
1538
1794
  smartAccount: z.ZodString;
1539
1795
  /** The signer that authorises the install (G... wallet). Used only for
@@ -1918,6 +2174,28 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
1918
2174
  [k: string]: unknown;
1919
2175
  };
1920
2176
  network?: "mainnet" | "testnet" | undefined;
2177
+ existingRules?: {
2178
+ signers: ({
2179
+ address: string;
2180
+ kind: "delegated";
2181
+ } | {
2182
+ kind: "external";
2183
+ verifier: string;
2184
+ keyBytes: string;
2185
+ })[];
2186
+ id: number;
2187
+ policyAddresses: string[];
2188
+ contextType: {
2189
+ kind: "default";
2190
+ } | {
2191
+ kind: "call_contract";
2192
+ contract: string;
2193
+ } | {
2194
+ kind: "create_contract";
2195
+ wasmHash: string;
2196
+ };
2197
+ predicate?: unknown;
2198
+ }[] | undefined;
1921
2199
  rpcUrl?: string | undefined;
1922
2200
  allowUnpinnedRpcUrl?: boolean | undefined;
1923
2201
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -1955,6 +2233,28 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
1955
2233
  [k: string]: unknown;
1956
2234
  };
1957
2235
  network?: "mainnet" | "testnet" | undefined;
2236
+ existingRules?: {
2237
+ signers: ({
2238
+ address: string;
2239
+ kind: "delegated";
2240
+ } | {
2241
+ kind: "external";
2242
+ verifier: string;
2243
+ keyBytes: string;
2244
+ })[];
2245
+ id: number;
2246
+ policyAddresses: string[];
2247
+ contextType: {
2248
+ kind: "default";
2249
+ } | {
2250
+ kind: "call_contract";
2251
+ contract: string;
2252
+ } | {
2253
+ kind: "create_contract";
2254
+ wasmHash: string;
2255
+ };
2256
+ predicate?: unknown;
2257
+ }[] | undefined;
1958
2258
  rpcUrl?: string | undefined;
1959
2259
  allowUnpinnedRpcUrl?: boolean | undefined;
1960
2260
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -1992,6 +2292,28 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
1992
2292
  [k: string]: unknown;
1993
2293
  };
1994
2294
  network?: "mainnet" | "testnet" | undefined;
2295
+ existingRules?: {
2296
+ signers: ({
2297
+ address: string;
2298
+ kind: "delegated";
2299
+ } | {
2300
+ kind: "external";
2301
+ verifier: string;
2302
+ keyBytes: string;
2303
+ })[];
2304
+ id: number;
2305
+ policyAddresses: string[];
2306
+ contextType: {
2307
+ kind: "default";
2308
+ } | {
2309
+ kind: "call_contract";
2310
+ contract: string;
2311
+ } | {
2312
+ kind: "create_contract";
2313
+ wasmHash: string;
2314
+ };
2315
+ predicate?: unknown;
2316
+ }[] | undefined;
1995
2317
  rpcUrl?: string | undefined;
1996
2318
  allowUnpinnedRpcUrl?: boolean | undefined;
1997
2319
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -2029,6 +2351,28 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
2029
2351
  [k: string]: unknown;
2030
2352
  };
2031
2353
  network?: "mainnet" | "testnet" | undefined;
2354
+ existingRules?: {
2355
+ signers: ({
2356
+ address: string;
2357
+ kind: "delegated";
2358
+ } | {
2359
+ kind: "external";
2360
+ verifier: string;
2361
+ keyBytes: string;
2362
+ })[];
2363
+ id: number;
2364
+ policyAddresses: string[];
2365
+ contextType: {
2366
+ kind: "default";
2367
+ } | {
2368
+ kind: "call_contract";
2369
+ contract: string;
2370
+ } | {
2371
+ kind: "create_contract";
2372
+ wasmHash: string;
2373
+ };
2374
+ predicate?: unknown;
2375
+ }[] | undefined;
2032
2376
  rpcUrl?: string | undefined;
2033
2377
  allowUnpinnedRpcUrl?: boolean | undefined;
2034
2378
  allowUnpinnedInterpreter?: boolean | undefined;