@crediolabs/policy-synth 0.1.14 → 0.1.15

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.
@@ -225,9 +225,9 @@ async function runVerifyPolicy(raw) {
225
225
  * Returns the unsigned Soroban transaction envelope (base64 XDR) the
226
226
  * wallet signs. The wallet signature IS the user-confirmation step - no
227
227
  * `action_id` two-call pair (the server is stateless, see server.ts:10-12).
228
- * Per design decision 4, only CALL 1 (account.add_context_rule) is
229
- * emitted; CALL 2 (interpreter.install) requires the rule id the account
230
- * assigns in call 1 and is documented under `followUp` in the response.
228
+ * One call installs the policy outright: `add_context_rule` carries the
229
+ * predicate to the interpreter in its `policies` install_param, so no
230
+ * separate `interpreter.install` call is needed or possible.
231
231
  *
232
232
  * Default-deny: an interpreter policy address other than the pinned
233
233
  * testnet interpreter is REFUSED (the smart account would delegate to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediolabs/policy-synth",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
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",
@@ -13,9 +13,12 @@
13
13
  // (b) key material the server does not have, so we ship the simpler ONE-CALL
14
14
  // shape. The wallet signature covers the change.
15
15
  //
16
- // `buildInstallPolicyXdr` returns CALL 1 ONLY. Call 2 (interpreter.install)
17
- // needs the rule id the account assigns in call 1, so it cannot be pre-built
18
- // and is documented in the response envelope under `followUp`.
16
+ // `buildInstallPolicyXdr` installs the policy in ONE call. `add_context_rule`
17
+ // takes `policies` as a `Map<policy_address, install_param>` and the account
18
+ // forwards each install_param to that policy, so the interpreter stores the
19
+ // predicate document as part of this same transaction. Earlier revisions
20
+ // documented a second `interpreter.install` call; that was wrong, and issuing
21
+ // it fails - the account re-enters the interpreter while it is mid-install.
19
22
 
20
23
  import { createHash } from 'node:crypto'
21
24
  import {
@@ -216,19 +219,17 @@ export interface BuildInstallPolicyResult {
216
219
  smartAccount: string
217
220
  /** Source account (echo) - the address that must sign. */
218
221
  sourceAccount: string
219
- /** The host-call target + fn name. Call 2 (interpreter.install) is NOT
220
- * emitted here; the account assigns the rule id in call 1 and call 2
221
- * needs that id to bind its `context_rule_ids`. See `followUp` below. */
222
+ /** The host-call target + fn name. This single call installs the policy
223
+ * outright: `add_context_rule` takes `policies` as a
224
+ * `Map<policy_address, install_param>`, and the account forwards each
225
+ * install_param to that policy. For an interpreter policy the param
226
+ * carries the predicate and its hash, so the interpreter stores the
227
+ * document as part of this transaction. There is no second call.
228
+ *
229
+ * Verified on testnet 2026-08-01: a rule created by this builder alone
230
+ * permits a matching operator call and denies a non-matching one with
231
+ * interpreter code #100 - not #206 MissingState. */
222
232
  call: { contract: string; fn: 'add_context_rule' }
223
- /** The follow-up call the caller MUST issue after this one confirms.
224
- * The rule id the account assigns in call 1 is required to bind the
225
- * interpreter's `install` auth context. */
226
- followUp: {
227
- contract: 'interpreter'
228
- fn: 'install'
229
- requiresRuleIdFromCallOne: true
230
- hint: string
231
- }
232
233
  /** Human-readable description of the install call, decoded FROM the
233
234
  * built unsigned XDR (not from the input args). The wallet signature
234
235
  * binds to bytes; the review card has to bind to the same bytes, so
@@ -243,9 +244,6 @@ export interface BuildInstallPolicyResult {
243
244
  rootInvocationXdr: string
244
245
  }
245
246
 
246
- const FOLLOWUP_HINT =
247
- 'after this tx confirms, read the rule id via account.get_context_rules_count()-1 (or get the receipt events), then call runInstallPolicy a second time with the interpreter as the target and the rule id in context_rule_ids - OR hand-build the install() call directly with the OZ auth pattern.'
248
-
249
247
  /** Build the unsigned transaction envelope for `account.add_context_rule(...)`.
250
248
  * The output XDR is signed by the wallet, not by us. */
251
249
  export async function buildInstallPolicyXdr(
@@ -363,12 +361,6 @@ export async function buildInstallPolicyXdr(
363
361
  smartAccount: args.smartAccount,
364
362
  sourceAccount: args.sourceAccount,
365
363
  call: { contract: args.smartAccount, fn: 'add_context_rule' },
366
- followUp: {
367
- contract: 'interpreter',
368
- fn: 'install',
369
- requiresRuleIdFromCallOne: true,
370
- hint: FOLLOWUP_HINT,
371
- },
372
364
  describes,
373
365
  authNonce: original.credentials().address().nonce().toString(),
374
366
  authValidUntilLedger: validUntilLedger,
package/src/run/index.ts CHANGED
@@ -300,9 +300,9 @@ export async function runVerifyPolicy(raw: unknown): Promise<ToolResponse<true>>
300
300
  * Returns the unsigned Soroban transaction envelope (base64 XDR) the
301
301
  * wallet signs. The wallet signature IS the user-confirmation step - no
302
302
  * `action_id` two-call pair (the server is stateless, see server.ts:10-12).
303
- * Per design decision 4, only CALL 1 (account.add_context_rule) is
304
- * emitted; CALL 2 (interpreter.install) requires the rule id the account
305
- * assigns in call 1 and is documented under `followUp` in the response.
303
+ * One call installs the policy outright: `add_context_rule` carries the
304
+ * predicate to the interpreter in its `policies` install_param, so no
305
+ * separate `interpreter.install` call is needed or possible.
306
306
  *
307
307
  * Default-deny: an interpreter policy address other than the pinned
308
308
  * testnet interpreter is REFUSED (the smart account would delegate to