@crediolabs/policy-synth 0.1.15 → 0.1.16

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.
@@ -18,7 +18,7 @@
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.VerifyPolicyInputSchema = exports.ToolErrorSchema = exports.SynthesizePolicyInputSchema = exports.SimulatePolicyInputSchema = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.OzAdapterConfigSchema = exports.OraclePriceFixtureSchema = exports.NetworkSchema = exports.MandateSpecSchema = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.ComposeUserResponsesSchema = void 0;
21
+ exports.VerifyPolicyInputSchema = exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.SimulatePolicyInputSchema = 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.OzAdapterConfigSchema = exports.OraclePriceFixtureSchema = exports.NetworkSchema = exports.MandateSpecSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.ComposeUserResponsesSchema = void 0;
22
22
  exports.runRecordTransaction = runRecordTransaction;
23
23
  exports.runSynthesizePolicy = runSynthesizePolicy;
24
24
  exports.runSimulatePolicy = runSimulatePolicy;
@@ -43,11 +43,14 @@ Object.defineProperty(exports, "ComposeUserResponsesSchema", { enumerable: true,
43
43
  Object.defineProperty(exports, "GetInterpreterInfoInputSchema", { enumerable: true, get: function () { return schemas_ts_2.GetInterpreterInfoInputSchema; } });
44
44
  Object.defineProperty(exports, "InstallPolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.InstallPolicyInputSchema; } });
45
45
  Object.defineProperty(exports, "InterpreterOptionsSchema", { enumerable: true, get: function () { return schemas_ts_2.InterpreterOptionsSchema; } });
46
+ Object.defineProperty(exports, "MAINNET_RPC_URL", { enumerable: true, get: function () { return schemas_ts_2.MAINNET_RPC_URL; } });
46
47
  Object.defineProperty(exports, "MandateSpecSchema", { enumerable: true, get: function () { return schemas_ts_2.MandateSpecSchema; } });
47
48
  Object.defineProperty(exports, "NetworkSchema", { enumerable: true, get: function () { return schemas_ts_2.NetworkSchema; } });
48
49
  Object.defineProperty(exports, "OraclePriceFixtureSchema", { enumerable: true, get: function () { return schemas_ts_2.OraclePriceFixtureSchema; } });
49
50
  Object.defineProperty(exports, "OzAdapterConfigSchema", { enumerable: true, get: function () { return schemas_ts_2.OzAdapterConfigSchema; } });
51
+ Object.defineProperty(exports, "PINNED_INTERPRETER_ADDRESS_BY_NETWORK", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_ADDRESS_BY_NETWORK; } });
50
52
  Object.defineProperty(exports, "PINNED_INTERPRETER_GRAMMAR_VERSION", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_GRAMMAR_VERSION; } });
53
+ Object.defineProperty(exports, "PINNED_INTERPRETER_MAINNET_ADDRESS", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_MAINNET_ADDRESS; } });
51
54
  Object.defineProperty(exports, "PINNED_INTERPRETER_TESTNET_ADDRESS", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_TESTNET_ADDRESS; } });
52
55
  Object.defineProperty(exports, "PINNED_INTERPRETER_WASM_SHA256", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_WASM_SHA256; } });
53
56
  Object.defineProperty(exports, "PredicateLeafSchema", { enumerable: true, get: function () { return schemas_ts_2.PredicateLeafSchema; } });
@@ -55,8 +58,10 @@ Object.defineProperty(exports, "PredicateNodeSchema", { enumerable: true, get: f
55
58
  Object.defineProperty(exports, "RecordedTransactionSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordedTransactionSchema; } });
56
59
  Object.defineProperty(exports, "RecordTransactionInputSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordTransactionInputSchema; } });
57
60
  Object.defineProperty(exports, "RevokePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.RevokePolicyInputSchema; } });
61
+ Object.defineProperty(exports, "RPC_URL_BY_NETWORK", { enumerable: true, get: function () { return schemas_ts_2.RPC_URL_BY_NETWORK; } });
58
62
  Object.defineProperty(exports, "SimulatePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.SimulatePolicyInputSchema; } });
59
63
  Object.defineProperty(exports, "SynthesizePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.SynthesizePolicyInputSchema; } });
64
+ Object.defineProperty(exports, "TESTNET_RPC_URL", { enumerable: true, get: function () { return schemas_ts_2.TESTNET_RPC_URL; } });
60
65
  Object.defineProperty(exports, "ToolErrorSchema", { enumerable: true, get: function () { return schemas_ts_2.ToolErrorSchema; } });
61
66
  Object.defineProperty(exports, "VerifyPolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.VerifyPolicyInputSchema; } });
62
67
  /** `record_transaction` body - wraps `recordTransaction`. The tool input
@@ -230,10 +235,12 @@ async function runVerifyPolicy(raw) {
230
235
  * separate `interpreter.install` call is needed or possible.
231
236
  *
232
237
  * Default-deny: an interpreter policy address other than the pinned
233
- * testnet interpreter is REFUSED (the smart account would delegate to
234
- * an interpreter the caller controls); the same applies to a non-pinned
235
- * RPC URL (the auth nonce the wallet signs comes from the RPC). Both
236
- * gates accept an explicit opt-in flag. */
238
+ * interpreter for the selected network is REFUSED (the smart account
239
+ * would delegate to an interpreter the caller controls); the same
240
+ * applies to a non-pinned RPC URL (the auth nonce the wallet signs
241
+ * comes from the RPC). Both gates accept an explicit opt-in flag.
242
+ * Pin selection follows `input.network` (defaults to `testnet` so the
243
+ * pre-mainnet callers keep working unchanged). */
237
244
  async function runInstallPolicy(raw) {
238
245
  const parsed = schemas_ts_1.InstallPolicyInputSchema.safeParse(raw);
239
246
  if (!parsed.success) {
@@ -243,17 +250,20 @@ async function runInstallPolicy(raw) {
243
250
  };
244
251
  }
245
252
  const input = parsed.data;
253
+ const network = input.network ?? 'testnet';
246
254
  // ---- Pinning gates (default-deny) ----
247
- const pinningError = enforceInterpreterPin(input.rule.policies, input.allowUnpinnedInterpreter);
255
+ const expectedInterpreter = schemas_ts_1.PINNED_INTERPRETER_ADDRESS_BY_NETWORK[network];
256
+ const expectedRpc = schemas_ts_1.RPC_URL_BY_NETWORK[network];
257
+ const pinningError = enforceInterpreterPin(input.rule.policies, input.allowUnpinnedInterpreter, expectedInterpreter);
248
258
  if (pinningError) {
249
259
  return { ok: false, error: pinningError };
250
260
  }
251
- if (input.rpcUrl && input.rpcUrl !== schemas_ts_1.TESTNET_RPC_URL && input.allowUnpinnedRpcUrl !== true) {
261
+ if (input.rpcUrl && input.rpcUrl !== expectedRpc && input.allowUnpinnedRpcUrl !== true) {
252
262
  return {
253
263
  ok: false,
254
264
  error: {
255
265
  code: 'INSTALL_BUILD_FAILED',
256
- message: `install_policy: rpcUrl must equal the pinned TESTNET_RPC_URL; set allowUnpinnedRpcUrl: true to opt in to a custom endpoint`,
266
+ message: `install_policy: rpcUrl must equal the pinned ${expectedRpc} (${network}); set allowUnpinnedRpcUrl: true to opt in to a custom endpoint`,
257
267
  severity: 'error',
258
268
  retryable: false,
259
269
  remediation: { toolCall: { name: 'install_policy', args: {} } },
@@ -262,7 +272,7 @@ async function runInstallPolicy(raw) {
262
272
  }
263
273
  let rpcClient;
264
274
  try {
265
- rpcClient = buildRpcClientFromInput(input.rpcUrl);
275
+ rpcClient = buildRpcClientFromInput(input.rpcUrl, network);
266
276
  }
267
277
  catch (e) {
268
278
  return {
@@ -279,7 +289,7 @@ async function runInstallPolicy(raw) {
279
289
  const result = await (0, build_install_policy_ts_1.buildInstallPolicyXdr)({
280
290
  smartAccount: input.smartAccount,
281
291
  sourceAccount: input.sourceAccount,
282
- networkPassphrase: schemas_ts_1.NETWORK_PASSPHRASES.testnet,
292
+ networkPassphrase: schemas_ts_1.NETWORK_PASSPHRASES[network],
283
293
  rule: input.rule,
284
294
  installNonce: input.installNonce,
285
295
  encodedPredicate,
@@ -303,7 +313,8 @@ async function runInstallPolicy(raw) {
303
313
  *
304
314
  * Same RPC pin as install: a non-pinned `rpcUrl` is refused unless
305
315
  * `allowUnpinnedRpcUrl: true`. Revoke does not carry an interpreter
306
- * policy payload, so the interpreter pin is not re-checked here. */
316
+ * policy payload, so the interpreter pin is not re-checked here.
317
+ * Pin selection follows `input.network` (defaults to `testnet`). */
307
318
  async function runRevokePolicy(raw) {
308
319
  const parsed = schemas_ts_1.RevokePolicyInputSchema.safeParse(raw);
309
320
  if (!parsed.success) {
@@ -313,12 +324,14 @@ async function runRevokePolicy(raw) {
313
324
  };
314
325
  }
315
326
  const input = parsed.data;
316
- if (input.rpcUrl && input.rpcUrl !== schemas_ts_1.TESTNET_RPC_URL && input.allowUnpinnedRpcUrl !== true) {
327
+ const network = input.network ?? 'testnet';
328
+ const expectedRpc = schemas_ts_1.RPC_URL_BY_NETWORK[network];
329
+ if (input.rpcUrl && input.rpcUrl !== expectedRpc && input.allowUnpinnedRpcUrl !== true) {
317
330
  return {
318
331
  ok: false,
319
332
  error: {
320
333
  code: 'REVOKE_BUILD_FAILED',
321
- message: `revoke_policy: rpcUrl must equal the pinned TESTNET_RPC_URL; set allowUnpinnedRpcUrl: true to opt in to a custom endpoint`,
334
+ message: `revoke_policy: rpcUrl must equal the pinned ${expectedRpc} (${network}); set allowUnpinnedRpcUrl: true to opt in to a custom endpoint`,
322
335
  severity: 'error',
323
336
  retryable: false,
324
337
  remediation: { toolCall: { name: 'revoke_policy', args: {} } },
@@ -327,7 +340,7 @@ async function runRevokePolicy(raw) {
327
340
  }
328
341
  let rpcClient;
329
342
  try {
330
- rpcClient = buildRpcClientFromInput(input.rpcUrl);
343
+ rpcClient = buildRpcClientFromInput(input.rpcUrl, network);
331
344
  }
332
345
  catch (e) {
333
346
  return {
@@ -340,7 +353,7 @@ async function runRevokePolicy(raw) {
340
353
  smartAccount: input.smartAccount,
341
354
  sourceAccount: input.sourceAccount,
342
355
  ruleId: input.ruleId,
343
- networkPassphrase: schemas_ts_1.NETWORK_PASSPHRASES.testnet,
356
+ networkPassphrase: schemas_ts_1.NETWORK_PASSPHRASES[network],
344
357
  rpc: rpcClient,
345
358
  ...(input.baseFee !== undefined ? { baseFee: input.baseFee } : {}),
346
359
  });
@@ -358,7 +371,15 @@ async function runRevokePolicy(raw) {
358
371
  * `grammar_version()` comparison. The audit field is deliberately
359
372
  * OMITTED (phase-04's "audit #44" has no source of truth in the repo -
360
373
  * fabricating it would be a lie on a security surface; the live
361
- * mismatch check is worth MORE). */
374
+ * mismatch check is worth MORE).
375
+ *
376
+ * Network-aware: `input.network` selects which interpreter pin and RPC
377
+ * to use. Mainnet was rolled out 2026-08-04 - the same wasm hash was
378
+ * uploaded to mainnet as was exercised on testnet, so a single
379
+ * `PINNED_INTERPRETER_WASM_SHA256` constant backs both networks
380
+ * (DEPLOYMENTS.md:25-27). The address differs because instance ids are
381
+ * network-scoped. UNAUDITED at the time of writing - see
382
+ * DEPLOYMENTS.md:29-32 for what is still pending. */
362
383
  async function runGetInterpreterInfo(raw) {
363
384
  const parsed = schemas_ts_1.GetInterpreterInfoInputSchema.safeParse(raw);
364
385
  if (!parsed.success) {
@@ -369,34 +390,15 @@ async function runGetInterpreterInfo(raw) {
369
390
  }
370
391
  const input = parsed.data;
371
392
  const network = input.network ?? 'testnet';
372
- // Asking about mainnet used to return the TESTNET pin with `network:
373
- // 'mainnet'` stamped on it. DEPLOYMENTS.md:3 says plainly "Testnet only.
374
- // Nothing is deployed to mainnet yet", so that answer described a contract
375
- // that does not exist at an address that is not on that network. This tool
376
- // exists to tell a caller what they are installing against; inventing a
377
- // mainnet deployment is the same failure as inventing an audit reference.
378
- if (network === 'mainnet') {
379
- return {
380
- ok: false,
381
- error: {
382
- code: 'RECORDING_FAILED',
383
- message: 'get_interpreter_info: no interpreter is deployed to mainnet. The pinned address and wasm hash are testnet-only; mainnet deployment is gated on the interpreter audit.',
384
- severity: 'error',
385
- retryable: false,
386
- remediation: {
387
- toolCall: { name: 'get_interpreter_info', args: { network: 'testnet' } },
388
- },
389
- },
390
- };
391
- }
393
+ const pinnedAddress = schemas_ts_1.PINNED_INTERPRETER_ADDRESS_BY_NETWORK[network];
392
394
  try {
393
395
  let deployedGrammarVersion;
394
396
  if (input.verifyLive === true) {
395
- const rpcClient = buildRpcClientFromInput(input.rpcUrl);
396
- deployedGrammarVersion = await rpcClient.getContractVersion(schemas_ts_1.PINNED_INTERPRETER_TESTNET_ADDRESS);
397
+ const rpcClient = buildRpcClientFromInput(input.rpcUrl, network);
398
+ deployedGrammarVersion = await rpcClient.getContractVersion(pinnedAddress);
397
399
  }
398
400
  const info = (0, get_interpreter_info_ts_1.getInterpreterInfo)({
399
- pinnedAddress: schemas_ts_1.PINNED_INTERPRETER_TESTNET_ADDRESS,
401
+ pinnedAddress,
400
402
  pinnedGrammarVersion: schemas_ts_1.PINNED_INTERPRETER_GRAMMAR_VERSION,
401
403
  pinnedWasmHash: schemas_ts_1.PINNED_INTERPRETER_WASM_SHA256,
402
404
  network,
@@ -411,41 +413,40 @@ async function runGetInterpreterInfo(raw) {
411
413
  };
412
414
  }
413
415
  }
414
- /** Build an InstallRpcClient from an optional URL override, falling back
415
- * to the public testnet RPC (matching the design-decision rule that we
416
- * reuse `record/rpc.ts` and never hard-code a different RPC client). */
417
- function buildRpcClientFromInput(urlOverride) {
418
- if (urlOverride) {
419
- return (0, build_install_policy_ts_1.rpcClientFromServer)(new stellar_sdk_1.rpc.Server(urlOverride, { allowHttp: false }), schemas_ts_1.NETWORK_PASSPHRASES.testnet);
420
- }
421
- // Default: public testnet RPC. Matches the brief; the mainnet pin would
422
- // need a separate deploy and is out of scope for this tool.
423
- //
416
+ /** Build an InstallRpcClient from an optional URL override + selected
417
+ * network, falling back to the pinned RPC for the network. The caller
418
+ * has already been gated against the pinned URL elsewhere, so the
419
+ * fallback here only ever picks from a finite, audited pair. */
420
+ function buildRpcClientFromInput(urlOverride, network) {
421
+ const url = urlOverride ?? schemas_ts_1.RPC_URL_BY_NETWORK[network];
422
+ const passphrase = schemas_ts_1.NETWORK_PASSPHRASES[network];
424
423
  // NOT `createRpcServer` - that returns an RpcFetcher, a bare
425
424
  // `(hash) => Promise<SorobanTxResponse|null>` for the RECORDER. Passing it
426
425
  // here produced a client whose `getAccount` was undefined, so every live
427
426
  // call died with "server.getAccount is not a function". The install path
428
427
  // needs the full Server surface.
429
- return (0, build_install_policy_ts_1.rpcClientFromServer)(new stellar_sdk_1.rpc.Server(schemas_ts_1.TESTNET_RPC_URL, { allowHttp: false }), schemas_ts_1.NETWORK_PASSPHRASES.testnet);
428
+ return (0, build_install_policy_ts_1.rpcClientFromServer)(new stellar_sdk_1.rpc.Server(url, { allowHttp: false }), passphrase);
430
429
  }
431
430
  /** Default-deny: refuse any interpreter policy whose address differs from
432
- * the pinned testnet interpreter. An interpreter the caller controls
433
- * can permit anything, so the smart account's authorization must bind
434
- * to the pinned contract unless the caller explicitly opts in via
435
- * `allowUnpinnedInterpreter`. OZ built-in policies are not interpreters
436
- * and pass through unchanged. Returns a ToolError to surface through
437
- * the run-layer envelope, or null when the policies are all pinned. */
438
- function enforceInterpreterPin(policies, allowUnpinned) {
431
+ * the pinned interpreter for the selected network. An interpreter the
432
+ * caller controls can permit anything, so the smart account's
433
+ * authorization must bind to the pinned contract unless the caller
434
+ * explicitly opts in via `allowUnpinnedInterpreter`. OZ built-in
435
+ * policies are not interpreters and pass through unchanged. Returns a
436
+ * ToolError to surface through the run-layer envelope, or null when the
437
+ * policies are all pinned. The caller resolves the expected pin per
438
+ * network; this function stays pure so it is easy to test. */
439
+ function enforceInterpreterPin(policies, allowUnpinned, expectedInterpreterAddress) {
439
440
  for (const p of policies) {
440
441
  if (p.kind !== 'interpreter')
441
442
  continue;
442
- if (p.interpreterAddress === schemas_ts_1.PINNED_INTERPRETER_TESTNET_ADDRESS)
443
+ if (p.interpreterAddress === expectedInterpreterAddress)
443
444
  continue;
444
445
  if (allowUnpinned === true)
445
446
  continue;
446
447
  return {
447
448
  code: 'INSTALL_BUILD_FAILED',
448
- message: `install_policy: interpreter policy address ${p.interpreterAddress} != pinned ${schemas_ts_1.PINNED_INTERPRETER_TESTNET_ADDRESS}; set allowUnpinnedInterpreter: true to opt in to a non-pinned interpreter`,
449
+ message: `install_policy: interpreter policy address ${p.interpreterAddress} != pinned ${expectedInterpreterAddress}; set allowUnpinnedInterpreter: true to opt in to a non-pinned interpreter`,
449
450
  severity: 'error',
450
451
  retryable: false,
451
452
  remediation: { toolCall: { name: 'install_policy', args: {} } },
@@ -2641,9 +2641,16 @@ export declare const VerifyPolicyInputSchema: z.ZodObject<{
2641
2641
  }> | undefined;
2642
2642
  }>;
2643
2643
  export type VerifyPolicyInput = z.infer<typeof VerifyPolicyInputSchema>;
2644
- /** Pinned interpreter address (testnet). Mirrors DEPLOYMENTS.md:156-157.
2644
+ /** Pinned interpreter address (testnet). Mirrors DEPLOYMENTS.md:128.
2645
2645
  * Single source for the MCP layer; do not embed elsewhere. */
2646
2646
  export declare const PINNED_INTERPRETER_TESTNET_ADDRESS = "CDR4NLV22STCXFGZPNKDQTEANWLF7LZ6AJLY6B7CLJXKHDZGYJWIOKGP";
2647
+ /** Pinned interpreter address (mainnet). Mirrors DEPLOYMENTS.md:18. Mainnet
2648
+ * has now been deployed (2026-08-04); the mainnet interpreter IS the binary
2649
+ * that was exercised on testnet (same wasm sha256, see
2650
+ * PINNED_INTERPRETER_WASM_SHA256). The address differs because instance
2651
+ * ids are network-scoped. UNAUDITED at the time of writing - see
2652
+ * DEPLOYMENTS.md:29-32 for the recorded decision and what is still pending. */
2653
+ export declare const PINNED_INTERPRETER_MAINNET_ADDRESS = "CALZAMUPREIRY4TULBEXIK77AUTOEJG63XLCPUWEHHQDOVK6ZVVS7VQ2";
2647
2654
  /** Pinned interpreter wasm sha256 (hex). Mirrors DEPLOYMENTS.md:156-157. */
2648
2655
  export declare const PINNED_INTERPRETER_WASM_SHA256 = "6e6c13d93e197aa380303a42cd120f5ddb080dd36ef2a343ee1dbd04ca52a443";
2649
2656
  /** The grammar version the interpreter enforces (matches SELF_VERSION in
@@ -2654,6 +2661,17 @@ export declare const PINNED_INTERPRETER_GRAMMAR_VERSION = 1;
2654
2661
  * than a Server; the two are deliberately different surfaces, so this is
2655
2662
  * pinned beside the addresses it is used with rather than shared. */
2656
2663
  export declare const TESTNET_RPC_URL = "https://soroban-testnet.stellar.org";
2664
+ /** Mainnet Soroban RPC. Pinned beside MAINNET counterparts so the install
2665
+ * and get_interpreter_info gates compare against the matching network's
2666
+ * RPC rather than always testnet. Public mainnet endpoint, the same one
2667
+ * the deploy script hit during the 2026-08-04 mainnet rollout. */
2668
+ export declare const MAINNET_RPC_URL = "https://mainnet.sorobanrpc.com";
2669
+ /** Pin + RPC lookup for the gate enforcement. The interpreters' wasm sha256
2670
+ * is identical across both networks (the same binary was uploaded both
2671
+ * places; DEPLOYMENTS.md:25-27), so `PINNED_INTERPRETER_WASM_SHA256` stays
2672
+ * a single constant - only the addresses and RPCs are network-scoped. */
2673
+ export declare const PINNED_INTERPRETER_ADDRESS_BY_NETWORK: Record<Network, string>;
2674
+ export declare const RPC_URL_BY_NETWORK: Record<Network, string>;
2657
2675
  /** Soroban `valid_until` window (ledgers) added to the latest ledger when
2658
2676
  * building the auth entry. ~25 minutes at 5s/ledger. */
2659
2677
  export declare const DEFAULT_AUTH_VALID_UNTIL_LEDGERS = 300;
@@ -2667,6 +2685,14 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
2667
2685
  /** The signer that authorises the install (G... wallet). Used only for
2668
2686
  * sequence number + auth nonce simulation; never persisted, never signed. */
2669
2687
  sourceAccount: z.ZodString;
2688
+ /** Target network for the install. Selects which interpreter pin and
2689
+ * which RPC URL are valid by default. Defaults to `testnet` so the
2690
+ * pre-mainnet callers keep working: they were always pointing at
2691
+ * the testnet pin, so defaulting testnet here is the conservative
2692
+ * continuation, NOT a silent fall-through that bypasses the gate.
2693
+ * A caller that targets mainnet MUST set this to `mainnet` (the
2694
+ * pin and RPC pin do not move by themselves). */
2695
+ network: z.ZodOptional<z.ZodEnum<["mainnet", "testnet"]>>;
2670
2696
  /** The proposed rule draft. Mirrors the core `ContextRuleDraft` shape. */
2671
2697
  rule: z.ZodEffects<z.ZodObject<{
2672
2698
  contextRuleType: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
@@ -3121,18 +3147,22 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
3121
3147
  }, z.ZodTypeAny, "passthrough">>;
3122
3148
  /** Per-rule install nonce; 1 for a fresh install. */
3123
3149
  installNonce: z.ZodNumber;
3124
- /** Optional RPC URL override. Defaults to the public testnet endpoint
3125
- * (`TESTNET_RPC_URL`); the override is refused unless
3150
+ /** Optional RPC URL override. Defaults to the pinned RPC for the
3151
+ * selected `network` (testnet by default, mainnet when
3152
+ * `network: 'mainnet'`); the override is refused unless
3126
3153
  * `allowUnpinnedRpcUrl: true`, because the auth nonce and
3127
3154
  * rootInvocation in the response come from whichever RPC answered. */
3128
3155
  rpcUrl: z.ZodOptional<z.ZodString>;
3129
3156
  /** Opt-in to using a non-pinned RPC URL. Without this flag the tool
3130
- * refuses any `rpcUrl` other than `TESTNET_RPC_URL` because the
3131
- * caller's auth-digest binds to whatever the RPC returned. */
3157
+ * refuses any `rpcUrl` other than the pinned RPC for the selected
3158
+ * network because the caller's auth-digest binds to whatever the
3159
+ * RPC returned. */
3132
3160
  allowUnpinnedRpcUrl: z.ZodOptional<z.ZodBoolean>;
3133
3161
  /** Opt-in to pointing the rule's interpreter policy at any address
3134
- * other than the pinned testnet interpreter. Default-deny: a caller
3135
- * that controls the interpreter can permit everything. */
3162
+ * other than the pinned interpreter for the selected network.
3163
+ * Default-deny: a caller that controls the interpreter can permit
3164
+ * everything. Selecting `network: 'mainnet'` is NOT an opt-in -
3165
+ * the mainnet pin is its own deny-by-default anchor. */
3136
3166
  allowUnpinnedInterpreter: z.ZodOptional<z.ZodBoolean>;
3137
3167
  /** Base fee in stroops; defaults to BASE_FEE (100). */
3138
3168
  baseFee: z.ZodOptional<z.ZodNumber>;
@@ -3175,6 +3205,7 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
3175
3205
  } & {
3176
3206
  [k: string]: unknown;
3177
3207
  };
3208
+ network?: "mainnet" | "testnet" | undefined;
3178
3209
  rpcUrl?: string | undefined;
3179
3210
  allowUnpinnedRpcUrl?: boolean | undefined;
3180
3211
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -3218,6 +3249,7 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
3218
3249
  } & {
3219
3250
  [k: string]: unknown;
3220
3251
  };
3252
+ network?: "mainnet" | "testnet" | undefined;
3221
3253
  rpcUrl?: string | undefined;
3222
3254
  allowUnpinnedRpcUrl?: boolean | undefined;
3223
3255
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -3261,6 +3293,7 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
3261
3293
  } & {
3262
3294
  [k: string]: unknown;
3263
3295
  };
3296
+ network?: "mainnet" | "testnet" | undefined;
3264
3297
  rpcUrl?: string | undefined;
3265
3298
  allowUnpinnedRpcUrl?: boolean | undefined;
3266
3299
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -3304,6 +3337,7 @@ export declare const InstallPolicyInputSchema: z.ZodEffects<z.ZodObject<{
3304
3337
  } & {
3305
3338
  [k: string]: unknown;
3306
3339
  };
3340
+ network?: "mainnet" | "testnet" | undefined;
3307
3341
  rpcUrl?: string | undefined;
3308
3342
  allowUnpinnedRpcUrl?: boolean | undefined;
3309
3343
  allowUnpinnedInterpreter?: boolean | undefined;
@@ -3318,9 +3352,12 @@ export declare const RevokePolicyInputSchema: z.ZodEffects<z.ZodObject<{
3318
3352
  * verify, since the account's source is not in this repo. Proven on
3319
3353
  * testnet: the account's deployer can revoke. */
3320
3354
  sourceAccount: z.ZodString;
3355
+ /** Target network for the revoke. Same `testnet`-default as install,
3356
+ * so pre-mainnet callers keep working without an explicit flag. */
3357
+ network: z.ZodOptional<z.ZodEnum<["mainnet", "testnet"]>>;
3321
3358
  /** The rule id to remove from the smart account + interpreter. */
3322
3359
  ruleId: z.ZodNumber;
3323
- /** Optional RPC URL override; same pin as install. */
3360
+ /** Optional RPC URL override; same per-network pin as install. */
3324
3361
  rpcUrl: z.ZodOptional<z.ZodString>;
3325
3362
  /** Opt-in to using a non-pinned RPC URL. Same semantics as install. */
3326
3363
  allowUnpinnedRpcUrl: z.ZodOptional<z.ZodBoolean>;
@@ -3330,6 +3367,7 @@ export declare const RevokePolicyInputSchema: z.ZodEffects<z.ZodObject<{
3330
3367
  smartAccount: string;
3331
3368
  sourceAccount: string;
3332
3369
  ruleId: number;
3370
+ network?: "mainnet" | "testnet" | undefined;
3333
3371
  rpcUrl?: string | undefined;
3334
3372
  allowUnpinnedRpcUrl?: boolean | undefined;
3335
3373
  baseFee?: number | undefined;
@@ -3337,6 +3375,7 @@ export declare const RevokePolicyInputSchema: z.ZodEffects<z.ZodObject<{
3337
3375
  smartAccount: string;
3338
3376
  sourceAccount: string;
3339
3377
  ruleId: number;
3378
+ network?: "mainnet" | "testnet" | undefined;
3340
3379
  rpcUrl?: string | undefined;
3341
3380
  allowUnpinnedRpcUrl?: boolean | undefined;
3342
3381
  baseFee?: number | undefined;
@@ -3344,6 +3383,7 @@ export declare const RevokePolicyInputSchema: z.ZodEffects<z.ZodObject<{
3344
3383
  smartAccount: string;
3345
3384
  sourceAccount: string;
3346
3385
  ruleId: number;
3386
+ network?: "mainnet" | "testnet" | undefined;
3347
3387
  rpcUrl?: string | undefined;
3348
3388
  allowUnpinnedRpcUrl?: boolean | undefined;
3349
3389
  baseFee?: number | undefined;
@@ -3351,6 +3391,7 @@ export declare const RevokePolicyInputSchema: z.ZodEffects<z.ZodObject<{
3351
3391
  smartAccount: string;
3352
3392
  sourceAccount: string;
3353
3393
  ruleId: number;
3394
+ network?: "mainnet" | "testnet" | undefined;
3354
3395
  rpcUrl?: string | undefined;
3355
3396
  allowUnpinnedRpcUrl?: boolean | undefined;
3356
3397
  baseFee?: number | undefined;
@@ -16,7 +16,7 @@
16
16
  // imports them here so its tool-shape bindings stay in step; the CLI imports
17
17
  // them here so it can build the same args envelope the MCP transport builds.
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.ToolErrorSchema = exports.GetInterpreterInfoInputSchema = exports.RevokePolicyInputSchema = exports.InstallPolicyInputSchema = exports.NETWORK_PASSPHRASES = exports.DEFAULT_AUTH_VALID_UNTIL_LEDGERS = exports.TESTNET_RPC_URL = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.VerifyPolicyInputSchema = exports.SimulatePolicyInputSchema = exports.OraclePriceFixtureSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.SynthesizePolicyInputSchema = exports.SynthesizePolicyRecordingInputSchema = exports.InterpreterOptionsSchema = exports.SynthesizePolicyMandateInputSchema = exports.RecordTransactionInputSchema = exports.OzAdapterConfigSchema = exports.ComposeUserResponsesSchema = exports.MandateSpecSchema = exports.RecordedTransactionSchema = exports.ParseConfidenceSchema = exports.OnChainEventSchema = exports.TokenMovementSchema = exports.ContractInvocationSchema = exports.ScValSchema = exports.NetworkSchema = void 0;
19
+ exports.ToolErrorSchema = exports.GetInterpreterInfoInputSchema = exports.RevokePolicyInputSchema = exports.InstallPolicyInputSchema = exports.NETWORK_PASSPHRASES = exports.DEFAULT_AUTH_VALID_UNTIL_LEDGERS = exports.RPC_URL_BY_NETWORK = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.MAINNET_RPC_URL = exports.TESTNET_RPC_URL = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.VerifyPolicyInputSchema = exports.SimulatePolicyInputSchema = exports.OraclePriceFixtureSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.SynthesizePolicyInputSchema = exports.SynthesizePolicyRecordingInputSchema = exports.InterpreterOptionsSchema = exports.SynthesizePolicyMandateInputSchema = exports.RecordTransactionInputSchema = exports.OzAdapterConfigSchema = exports.ComposeUserResponsesSchema = exports.MandateSpecSchema = exports.RecordedTransactionSchema = exports.ParseConfidenceSchema = exports.OnChainEventSchema = exports.TokenMovementSchema = exports.ContractInvocationSchema = exports.ScValSchema = exports.NetworkSchema = void 0;
20
20
  const zod_1 = require("zod");
21
21
  const address_ts_1 = require("../synth/address.js");
22
22
  /** Soroban `valid_until` is a u32 ledger sequence; a value above this cannot be
@@ -427,9 +427,16 @@ const MandateSpecSchemaForRule = zod_1.z
427
427
  // install/revoke/get_info schemas live HERE (after the helper) so the const
428
428
  // reference resolves at module init. They are the new tools on top of the
429
429
  // existing four.
430
- /** Pinned interpreter address (testnet). Mirrors DEPLOYMENTS.md:156-157.
430
+ /** Pinned interpreter address (testnet). Mirrors DEPLOYMENTS.md:128.
431
431
  * Single source for the MCP layer; do not embed elsewhere. */
432
432
  exports.PINNED_INTERPRETER_TESTNET_ADDRESS = 'CDR4NLV22STCXFGZPNKDQTEANWLF7LZ6AJLY6B7CLJXKHDZGYJWIOKGP';
433
+ /** Pinned interpreter address (mainnet). Mirrors DEPLOYMENTS.md:18. Mainnet
434
+ * has now been deployed (2026-08-04); the mainnet interpreter IS the binary
435
+ * that was exercised on testnet (same wasm sha256, see
436
+ * PINNED_INTERPRETER_WASM_SHA256). The address differs because instance
437
+ * ids are network-scoped. UNAUDITED at the time of writing - see
438
+ * DEPLOYMENTS.md:29-32 for the recorded decision and what is still pending. */
439
+ exports.PINNED_INTERPRETER_MAINNET_ADDRESS = 'CALZAMUPREIRY4TULBEXIK77AUTOEJG63XLCPUWEHHQDOVK6ZVVS7VQ2';
433
440
  /** Pinned interpreter wasm sha256 (hex). Mirrors DEPLOYMENTS.md:156-157. */
434
441
  exports.PINNED_INTERPRETER_WASM_SHA256 = '6e6c13d93e197aa380303a42cd120f5ddb080dd36ef2a343ee1dbd04ca52a443';
435
442
  /** The grammar version the interpreter enforces (matches SELF_VERSION in
@@ -440,6 +447,23 @@ exports.PINNED_INTERPRETER_GRAMMAR_VERSION = 1;
440
447
  * than a Server; the two are deliberately different surfaces, so this is
441
448
  * pinned beside the addresses it is used with rather than shared. */
442
449
  exports.TESTNET_RPC_URL = 'https://soroban-testnet.stellar.org';
450
+ /** Mainnet Soroban RPC. Pinned beside MAINNET counterparts so the install
451
+ * and get_interpreter_info gates compare against the matching network's
452
+ * RPC rather than always testnet. Public mainnet endpoint, the same one
453
+ * the deploy script hit during the 2026-08-04 mainnet rollout. */
454
+ exports.MAINNET_RPC_URL = 'https://mainnet.sorobanrpc.com';
455
+ /** Pin + RPC lookup for the gate enforcement. The interpreters' wasm sha256
456
+ * is identical across both networks (the same binary was uploaded both
457
+ * places; DEPLOYMENTS.md:25-27), so `PINNED_INTERPRETER_WASM_SHA256` stays
458
+ * a single constant - only the addresses and RPCs are network-scoped. */
459
+ exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = {
460
+ testnet: exports.PINNED_INTERPRETER_TESTNET_ADDRESS,
461
+ mainnet: exports.PINNED_INTERPRETER_MAINNET_ADDRESS,
462
+ };
463
+ exports.RPC_URL_BY_NETWORK = {
464
+ testnet: exports.TESTNET_RPC_URL,
465
+ mainnet: exports.MAINNET_RPC_URL,
466
+ };
443
467
  /** Soroban `valid_until` window (ledgers) added to the latest ledger when
444
468
  * building the auth entry. ~25 minutes at 5s/ledger. */
445
469
  exports.DEFAULT_AUTH_VALID_UNTIL_LEDGERS = 300;
@@ -457,22 +481,34 @@ exports.InstallPolicyInputSchema = zod_1.z
457
481
  /** The signer that authorises the install (G... wallet). Used only for
458
482
  * sequence number + auth nonce simulation; never persisted, never signed. */
459
483
  sourceAccount: zod_1.z.string(),
484
+ /** Target network for the install. Selects which interpreter pin and
485
+ * which RPC URL are valid by default. Defaults to `testnet` so the
486
+ * pre-mainnet callers keep working: they were always pointing at
487
+ * the testnet pin, so defaulting testnet here is the conservative
488
+ * continuation, NOT a silent fall-through that bypasses the gate.
489
+ * A caller that targets mainnet MUST set this to `mainnet` (the
490
+ * pin and RPC pin do not move by themselves). */
491
+ network: exports.NetworkSchema.optional(),
460
492
  /** The proposed rule draft. Mirrors the core `ContextRuleDraft` shape. */
461
493
  rule: MandateSpecSchemaForRule,
462
494
  /** Per-rule install nonce; 1 for a fresh install. */
463
495
  installNonce: zod_1.z.number().int().positive(),
464
- /** Optional RPC URL override. Defaults to the public testnet endpoint
465
- * (`TESTNET_RPC_URL`); the override is refused unless
496
+ /** Optional RPC URL override. Defaults to the pinned RPC for the
497
+ * selected `network` (testnet by default, mainnet when
498
+ * `network: 'mainnet'`); the override is refused unless
466
499
  * `allowUnpinnedRpcUrl: true`, because the auth nonce and
467
500
  * rootInvocation in the response come from whichever RPC answered. */
468
501
  rpcUrl: zod_1.z.string().url().optional(),
469
502
  /** Opt-in to using a non-pinned RPC URL. Without this flag the tool
470
- * refuses any `rpcUrl` other than `TESTNET_RPC_URL` because the
471
- * caller's auth-digest binds to whatever the RPC returned. */
503
+ * refuses any `rpcUrl` other than the pinned RPC for the selected
504
+ * network because the caller's auth-digest binds to whatever the
505
+ * RPC returned. */
472
506
  allowUnpinnedRpcUrl: zod_1.z.boolean().optional(),
473
507
  /** Opt-in to pointing the rule's interpreter policy at any address
474
- * other than the pinned testnet interpreter. Default-deny: a caller
475
- * that controls the interpreter can permit everything. */
508
+ * other than the pinned interpreter for the selected network.
509
+ * Default-deny: a caller that controls the interpreter can permit
510
+ * everything. Selecting `network: 'mainnet'` is NOT an opt-in -
511
+ * the mainnet pin is its own deny-by-default anchor. */
476
512
  allowUnpinnedInterpreter: zod_1.z.boolean().optional(),
477
513
  /** Base fee in stroops; defaults to BASE_FEE (100). */
478
514
  baseFee: zod_1.z.number().int().positive().optional(),
@@ -489,9 +525,12 @@ exports.RevokePolicyInputSchema = zod_1.z
489
525
  * verify, since the account's source is not in this repo. Proven on
490
526
  * testnet: the account's deployer can revoke. */
491
527
  sourceAccount: zod_1.z.string(),
528
+ /** Target network for the revoke. Same `testnet`-default as install,
529
+ * so pre-mainnet callers keep working without an explicit flag. */
530
+ network: exports.NetworkSchema.optional(),
492
531
  /** The rule id to remove from the smart account + interpreter. */
493
532
  ruleId: zod_1.z.number().int().nonnegative(),
494
- /** Optional RPC URL override; same pin as install. */
533
+ /** Optional RPC URL override; same per-network pin as install. */
495
534
  rpcUrl: zod_1.z.string().url().optional(),
496
535
  /** Opt-in to using a non-pinned RPC URL. Same semantics as install. */
497
536
  allowUnpinnedRpcUrl: zod_1.z.boolean().optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediolabs/policy-synth",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "license": "MIT",
5
5
  "description": "Off-chain TypeScript synthesis core for the OZ Accounts Policy Builder. Records Soroban transactions, synthesises the minimal policy that permits exactly that flow, verifies it, and returns an unsigned install transaction.",
6
6
  "type": "module",