@pushchain/core 6.0.27-alpha.0 → 6.0.27-alpha.2

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 (82) hide show
  1. package/AGW.md +104 -19
  2. package/CHANGELOG.md +16 -0
  3. package/package.json +1 -1
  4. package/src/lib/agentic/agentic.types.d.ts +8 -3
  5. package/src/lib/agentic/capabilities.d.ts +1 -1
  6. package/src/lib/agentic/capabilities.js +1 -1
  7. package/src/lib/agentic/codec/abi-layout.d.ts +5 -0
  8. package/src/lib/agentic/codec/abi-layout.js +50 -3
  9. package/src/lib/agentic/codec/defaults.d.ts +2 -2
  10. package/src/lib/agentic/codec/defaults.js +2 -2
  11. package/src/lib/agentic/codec/ids.d.ts +1 -1
  12. package/src/lib/agentic/codec/ids.js +1 -1
  13. package/src/lib/agentic/codec/native.d.ts +4 -6
  14. package/src/lib/agentic/codec/native.js +27 -14
  15. package/src/lib/agentic/codec/pins.d.ts +20 -0
  16. package/src/lib/agentic/codec/pins.js +29 -0
  17. package/src/lib/agentic/codec/rules.d.ts +1 -1
  18. package/src/lib/agentic/codec/rules.js +3 -3
  19. package/src/lib/agentic/codec/session.d.ts +2 -2
  20. package/src/lib/agentic/codec/session.js +3 -3
  21. package/src/lib/agentic/codec/svm-terms.d.ts +1 -1
  22. package/src/lib/agentic/codec/svm-terms.js +7 -3
  23. package/src/lib/agentic/codec/universal-terms.d.ts +15 -0
  24. package/src/lib/agentic/codec/universal-terms.js +2 -0
  25. package/src/lib/agentic/codec/universal.js +22 -6
  26. package/src/lib/agentic/constants.d.ts +1 -0
  27. package/src/lib/agentic/constants.js +1 -0
  28. package/src/lib/agentic/contracts/abi/{v5 → v6}/agent-validator.js +1 -1
  29. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw-factory.d.ts +299 -0
  30. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw-factory.js +393 -2
  31. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw.d.ts +96 -1
  32. package/src/lib/agentic/contracts/abi/{v5 → v6}/agw.js +128 -3
  33. package/src/lib/agentic/contracts/abi/{v5 → v6}/index.d.ts +1 -1
  34. package/src/lib/agentic/contracts/abi/{v5 → v6}/index.js +3 -3
  35. package/src/lib/agentic/contracts/abi/{v5 → v6}/smart-session.js +1 -1
  36. package/src/lib/agentic/contracts/abi/{v5 → v6}/universal-rules-policy.d.ts +329 -308
  37. package/src/lib/agentic/contracts/abi/{v5 → v6}/universal-rules-policy.js +396 -369
  38. package/src/lib/agentic/contracts/donut-v6.d.ts +11 -0
  39. package/src/lib/agentic/contracts/donut-v6.js +15 -0
  40. package/src/lib/agentic/contracts/{v5.d.ts → v6.d.ts} +800 -384
  41. package/src/lib/agentic/contracts/{v5.js → v6.js} +60 -33
  42. package/src/lib/agentic/deployments.d.ts +5 -5
  43. package/src/lib/agentic/deployments.js +19 -19
  44. package/src/lib/agentic/errors.d.ts +1 -7
  45. package/src/lib/agentic/errors.js +1 -9
  46. package/src/lib/agentic/execution/outbound.d.ts +4 -4
  47. package/src/lib/agentic/execution/outbound.js +5 -5
  48. package/src/lib/agentic/execution/send.js +3 -11
  49. package/src/lib/agentic/execution/svm-outbound.d.ts +1 -1
  50. package/src/lib/agentic/execution/svm-payload.js +1 -1
  51. package/src/lib/agentic/execution/svm-public.js +1 -7
  52. package/src/lib/agentic/execution/svm-send.d.ts +1 -1
  53. package/src/lib/agentic/execution/svm-send.js +0 -3
  54. package/src/lib/agentic/index.d.ts +2 -2
  55. package/src/lib/agentic/management/common.js +7 -5
  56. package/src/lib/agentic/management/create.d.ts +1 -13
  57. package/src/lib/agentic/management/create.js +24 -157
  58. package/src/lib/agentic/management/svm.js +2 -2
  59. package/src/lib/agentic/presets/aave-reserves.d.ts +4 -0
  60. package/src/lib/agentic/presets/aave-reserves.js +147 -0
  61. package/src/lib/agentic/presets/catalog.d.ts +30 -3
  62. package/src/lib/agentic/presets/catalog.js +344 -3
  63. package/src/lib/agentic/presets/index.js +186 -22
  64. package/src/lib/agentic/presets/operation-limits.d.ts +13 -0
  65. package/src/lib/agentic/presets/operation-limits.js +111 -0
  66. package/src/lib/agentic/presets/types.d.ts +44 -9
  67. package/src/lib/agentic/public-rule.d.ts +2 -2
  68. package/src/lib/agentic/public-rule.js +24 -40
  69. package/src/lib/agentic/reads/rules.js +27 -11
  70. package/src/lib/agentic/reads/svm.d.ts +1 -1
  71. package/src/lib/agentic/reads/svm.js +2 -2
  72. package/src/lib/agentic/response.js +7 -7
  73. package/src/lib/agentic/revert.js +5 -5
  74. package/src/lib/agentic/runtime.js +12 -3
  75. package/src/lib/agentic/utils.js +1 -1
  76. package/src/lib/constants/index.d.ts +1 -0
  77. package/src/lib/index.d.ts +2 -2
  78. package/src/lib/push-chain/push-chain.d.ts +1 -0
  79. package/src/lib/agentic/contracts/donut-v5.d.ts +0 -11
  80. package/src/lib/agentic/contracts/donut-v5.js +0 -15
  81. /package/src/lib/agentic/contracts/abi/{v5 → v6}/agent-validator.d.ts +0 -0
  82. /package/src/lib/agentic/contracts/abi/{v5 → v6}/smart-session.d.ts +0 -0
package/AGW.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agentic wallets on Push Chain
2
2
 
3
- This branch implements the SDK-only October 12 feedback against the deployed Donut v5 contracts. Contract-dependent changes remain explicit below.
3
+ This branch implements the SDK-only October 12 feedback against the deployed Donut v6 contracts. The runtime targets v6 only; existing v5 wallets are not silently adapted.
4
4
 
5
5
  ## Connect
6
6
 
@@ -83,15 +83,15 @@ async function manage(owner: PushChain, address: Address, id: Hex) {
83
83
 
84
84
  `create` and `rules.add` reject a duplicate agent/chain pair with `DUPLICATE_RULE`. Put several permitted calls in the same rule. Existing overlapping grants can still cause `AMBIGUOUS_RULE` when sending; the owner must resolve the overlap. The contract validates every actual agent call.
85
85
 
86
- On deployed v5, native rules allow at most **eight** calls, eight equality pins and one maximum pin per call. Public native lifetime budgets, `maxCalls`, `amount`, single-call shorthand and `actions[]` are retired. Native counters still accumulate for reporting and atomic update assertions.
86
+ On deployed v6, native rules allow at most **eight** calls, eight equality/maximum pins per call. Public native lifetime budgets, `maxCalls`, `amount`, single-call shorthand and `actions[]` are retired. Native value and call counters accumulate for reporting and atomic updates. A v6 MAX pin only bounds an individual call and does not increment amountSpent; that counter belongs to the separate internal amount meter.
87
87
 
88
88
  ## Pins and zero defaults
89
89
 
90
- An equality pin fixes an argument; a maximum pin bounds it. For EVM signatures, `arg` is a zero-based static argument position. With a raw four-byte selector, it is a 32-byte ABI head-word position. Reads return a raw selector and these word positions. Unsupported dynamic/compound layouts fail explicitly; no guessed tuple-field indexes are produced.
90
+ An equality pin fixes an argument; a maximum pin bounds it. For EVM signatures, `arg` is a zero-based static argument position. With a raw four-byte selector, it is a 32-byte ABI head-word position. Reads return a raw selector and these word positions. For full signatures, a path such as `arg: [0, 3]` selects a field within a static tuple or fixed array. Dynamic layouts fail explicitly. Reads retain exact word positions rather than guessing missing ABI metadata.
91
91
 
92
92
  `PushChain.CONSTANTS.AGENTIC.WALLET` resolves to the AGW on Push, its CEA on an EVM destination, or its CEA/selected token ATA on Solana. Deployment addresses and encoding helpers are internal.
93
93
 
94
- Omitted `maxValue`, `assets[].maxTotal`, and `maxGasPerCall` default to **zero**, which permits no corresponding movement. Specify positive caps for sends that need value, tokens or destination gas. Native value is limited per call; there is no public native lifetime-total cap.
94
+ Omitted `maxValue`, `assets[].maxTotal`, and `maxGasPerCall` default to **zero**. Asset totals meter tokens sent from Push; they do not meter trading or lending using capital already in the destination CEA. Specify positive caps for sends that need value, tokens or destination gas. Native value is limited per call; there is no public native lifetime-total cap.
95
95
 
96
96
  ## EVM destinations
97
97
 
@@ -112,7 +112,7 @@ function evmRule(agent: Address, target: Address): Rule {
112
112
  }
113
113
  ```
114
114
 
115
- The deployed policy supports one `WALLET` equality pin per EVM destination call. General destination equality/maximum pins need the new contract deployment and currently fail with `CAPABILITY_UNAVAILABLE` before signing.
115
+ The deployed v6 policy supports up to eight EQ/MAX pins per EVM destination call and 32 across the rule. Multiple entries for the same target/function are alternatives; every constraint in one entry must pass. The SDK rejects a bare alternative beside a pinned one because it would bypass the pins.
116
116
 
117
117
  When the caller omits destination `gasLimit`, a fresh EVM CEA gets a 2,000,000 gas default to cover first-use deployment. An existing CEA uses the normal quote default. An explicit caller value is preserved. The rule's gas/value caps still apply.
118
118
 
@@ -153,19 +153,26 @@ Connect with `PushChain.initialize(signer, { agenticWallet: address })` to send
153
153
 
154
154
  Updates assert existing spend, delete the old rule and grant its replacement atomically. Native updates assert each action separately: a rule with N native actions records N+4 checkpoints on current v5. Agent execution records no owner checkpoint. Direct `setLabel` records none.
155
155
 
156
- ## Deployment-dependent behavior
156
+ ## V6 deployment and creation
157
157
 
158
- The October 12 contract feedback is not deployed. Until it is verified:
158
+ The runtime uses factory `0xFBBEB6a365178fAaA81A9789a5f64b300c37e5bc` and URP `0xBA32e7A1500cb34311a31127bcD40CA52C8CFd36`, from source `ffd567d`. URP still reports 3.1.0; verified deployment wiring and the v6 ABI identify the supported generation.
159
159
 
160
- - Outbound sends on both doors require a separately owner-set gateway allowance; the SDK never silently creates or restores one. Insufficient allowance fails before signing.
161
- - Creation uses the existing index-bound deploy/grant flow. If a signer cannot execute it atomically, `CREATE_PARTIAL` preserves committed receipts and recovery details. Do not blindly retry creation.
162
- - General EVM destination pins and the new atomic factory `createWallet` are unavailable.
160
+ `create` uses one index-bound `createWalletWithSig` call from the owner's Push identity, with the contract's owner-caller empty-signature path. The wallet and up to eight initial rules are committed atomically. A concurrent slot change returns INDEX_RACE; a receipt-read failure retains the submitted hash for recovery. CREATE_PARTIAL is removed. No sequential creation fallback exists.
163
161
 
164
- `rules.delete` is the public name; on-chain `revokeRules` names/events remain unchanged. Unsupported capabilities use `CAPABILITY_UNAVAILABLE`. On-chain errors retain revert details through `AgenticRevertError`/`PushChainExecutionError`.
162
+ For outbound sends on either door, the wallet approves the gateway inside the transaction after policy authorization, executes the outbound, and clears remaining allowance. No separate approval or SDK allowance check is needed; GATEWAY_ALLOWANCE_INSUFFICIENT is removed. Approval/cleanup uses the contract's best-effort token calls. To stop an agent, delete its rules; clearing the gateway allowance does not disable an otherwise valid rule.
163
+
164
+ The wire encoder uses uint32 maximum for unlimited native calls and 255 for unspecified Solana account count. Neither uses the retired zero sentinel. The envelope remains version 1. Existing v5 wallets and addresses do not become v6 wallets.
165
+
166
+ `rules.delete` is the public name; on-chain `revokeRules` names/events remain unchanged. Revert errors retain decoded details and cause. Core transaction response fields used by other SDK routes are not globally removed.
165
167
 
166
168
  ## Preset discovery and templates (section 7)
167
169
 
168
- `PushChain.utils.agentic` contains only `presets.list/get`. The enumerable categories are `AGENTIC.PRESETS.CATEGORY.DEXES`, `LENDING` and `PREDICTION`. All three currently have empty `chains` lists because the app/address catalog is not approved yet; hide them in a UI. No production DEX/lending addresses ship in this framework.
170
+ `PushChain.utils.agentic` contains `presets.list/get`. The categories are `AGENTIC.PRESETS.CATEGORY.DEXES`, `LENDING`, `STAKING` and `PREDICTION`. The catalog includes mainnet and testnet templates. Discovery is network-independent: pass `chainNamespace` to select the intended chain. A mainnet template does not imply that the connected Push network supports execution to it:
171
+
172
+ - DEXES: Uniswap V3 on Ethereum, Base and Arbitrum (mainnet and their Sepolia testnets); PancakeSwap V3 on BNB mainnet and BSC testnet.
173
+ - LENDING: Aave on Ethereum, Base, Arbitrum and BNB mainnets, plus Sepolia/Base Sepolia/Arbitrum Sepolia; Moonwell on Base mainnet/testnet and Venus on BNB mainnet/testnet.
174
+ - STAKING: EigenLayer deposits on Ethereum mainnet and Sepolia; Lido stake and wrap/unwrap on Ethereum mainnet. Withdrawal requests with dynamic amounts, claims with position-derived amounts and EigenLayer withdrawals are excluded from these bounded presets. A selected native asset supplies the Lido `submit` value cap; omitted caps remain zero.
175
+ - PREDICTION: no entries yet. Hide categories with empty `chains` lists.
169
176
 
170
177
  ```ts
171
178
  const { presets } = PushChain.utils.agentic.presets.list({ type: 'CATEGORY' });
@@ -173,22 +180,100 @@ const availablePresets = presets.filter(preset => preset.chains.length > 0);
173
180
  const { rules: reviewTemplates } = PushChain.utils.agentic.presets.get(
174
181
  PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES,
175
182
  );
176
- // Currently [], since there is no approved catalog. Never treat an empty result as an active preset.
183
+ // Choose tokens in the review UI, then call get again as below.
177
184
 
178
- function filledPreset(agent: Address) {
185
+ function filledPreset(agent: Address, tokenIn: Address, tokenOut: Address) {
179
186
  return PushChain.utils.agentic.presets.get(
180
187
  PushChain.CONSTANTS.AGENTIC.PRESETS.CATEGORY.DEXES,
181
- { agent, validUntil: Math.floor(Date.now() / 1000) + 3600 },
182
- ).rules;
188
+ {
189
+ chainNamespace: 'eip155:11155111',
190
+ agent,
191
+ validUntil: Math.floor(Date.now() / 1000) + 3600,
192
+ maxGasPerCall: BigInt(10) ** BigInt(18),
193
+ assets: [
194
+ { token: tokenIn, maxPerCall: BigInt(100), maxTotal: BigInt(1000) },
195
+ { token: tokenOut, maxPerCall: BigInt(100), maxTotal: BigInt(1000) },
196
+ ],
197
+ },
198
+ );
183
199
  }
184
200
  ```
185
201
 
186
- With catalog entries, `get` groups calls into one rule per chain. With agent and expiry supplied, its return type is `Rule[]`; otherwise it is `PresetRuleTemplate[]`, requiring those fields before `create`. Assets must name their chain unless a single chain filter is supplied. Missing `maxPerCall` or `maxTotal` defaults to zero (user decision, October 12), so missing caps do not grant token movement.
202
+ The example caps are illustrative raw units; choose caps for the actual token decimals and gas requirements. `get` groups calls into one rule per chain. The result is `{ rules, readiness }`. With agent and expiry supplied, `rules` is typed as `Rule[]`; otherwise it is `PresetRuleTemplate[]`. This type distinction alone does not establish readiness. Assets must name their chain unless a single chain filter is supplied. Omitted asset caps and `maxGasPerCall` default to zero.
203
+
204
+ DEX discovery works without options, with an empty asset list, or with assets for only some chains. A chain with fewer than two tokens returns full-signature review calls with wallet-recipient pins and an explicit zero input-amount maximum. A single supplied token is also pinned as the input. These calls cannot spend swap input tokens, even if asset budgets are filled later. Call `get` again after selecting both tokens to replace the review calls with the complete token-pinned rules; merely assigning `rule.assets` is insufficient.
205
+
206
+ With two ERC20 tokens, `get` expands ordered pairs into exact-input and exact-output calls with token, wallet-recipient and input-amount pins. Native markers and expansions exceeding the policy's 32-pin limit are rejected. Two tokens fit the shipped router template; three do not. Static tuple fields use paths such as `[0, 3]`.
207
+
208
+ Reviewed EVM spenders generate approvals pinned to that spender and bounded by the asset's per-call cap. Money-market approvals are restricted to the market's underlying token. Distinct spenders become separate pinned alternatives under v6. These destination approvals are ordinary ERC20 allowances; the wallet's automatic Push-side gateway approval is separate.
187
209
 
188
- Reviewed EVM catalog spenders generate approvals pinned to that spender and bounded by the asset's per-call cap. Native assets need no approval. Conflicting spenders for the same token are rejected until the policy representation is reviewed; the framework never replaces them with an unrestricted approval. General EVM approval pins still require the pending contract upgrade, and normal `create/add` validation enforces that boundary. Presets do not sign, fetch app ABIs or modify wallets.
210
+ Templates describe permissions, not available liquidity or guaranteed execution. Verify destination token balances, supported reserves and source PRC20 routes before use: protocol testnet mock tokens may differ from MOVEABLE tokens. Presets do not sign, fetch app ABIs or modify wallets. Dynamic-path swaps, Solana protocol templates and unconfirmed deployments are excluded. Mainnet addresses were checked read-only; no mainnet transactions were executed. Other mainnet protocols in the proposal remain excluded until their deployment and permission constraints are verified. Local policy tests do not execute the destination protocols.
189
211
 
190
- The remaining catalog work includes selecting verified apps/functions/chains, struct-field indexing and checking approval combinations against the delivered policy. App ABIs remain with the UI.
212
+ ### Configure, inspect and regenerate
213
+
214
+ `readiness.ready` means the returned chains have locally complete inputs and at least one enabled asset operation. It does not check PRC20 availability, deployments, balances, live reserve flags or liquidity. `readiness.chains` gives per-chain `issues`, `disabledCalls`, `excludedCalls`, catalog `knownTokens` and `zeroBridgeLimits`. These are additive result fields; `rules` remains accepted by the existing create/update methods.
215
+
216
+ The UI should collect chain, agent, token selections, raw-unit limits, gas budget and expiry. Show zero-cap calls as disabled. Present excluded calls explicitly. There is no SDK-selected 0.1 PC gas budget or 30-day expiry. A zero bridge limit can be intentional when assets are already at the destination; it is reported separately from operation readiness.
217
+
218
+ ```ts
219
+ async function createConfiguredDex(
220
+ client: PushChain, agent: Address, tokenIn: Address, tokenOut: Address,
221
+ ) {
222
+ const configured = filledPreset(agent, tokenIn, tokenOut);
223
+ if (!configured.readiness.ready) {
224
+ // Render these issues in the configuration screen; do not present it as ready.
225
+ return { issues: configured.readiness.chains };
226
+ }
227
+ return client.agentic.create('My DEX agent', { rules: configured.rules });
228
+ }
229
+
230
+ async function replaceConfiguredDex(
231
+ client: PushChain, wallet: Address, rulesId: Hex,
232
+ agent: Address, tokenIn: Address, tokenOut: Address,
233
+ ) {
234
+ // Re-run get after editing tokens or limits. Changing rule.assets alone
235
+ // does not regenerate allowedCalls, token pins or approvals.
236
+ const configured = filledPreset(agent, tokenIn, tokenOut);
237
+ if (!configured.readiness.ready) throw new Error('Complete the preset inputs');
238
+ return client.agentic.wallet(wallet).rules.update({
239
+ rules: [{ rulesId, rule: configured.rules[0] }],
240
+ });
241
+ }
242
+ ```
243
+
244
+ Save the preset category and editable inputs in the UI if subsequent edits should regenerate the preset. On-chain rules do not retain preset provenance or display metadata. A regenerated result is a replacement: do not append it to the old allowedCalls or keep the old token approvals. An update creates a new rulesId and resets counters, as documented above.
245
+
246
+ ### Amount units and enforcement scope
247
+
248
+ | Preset operation | Generated restriction |
249
+ | --- | --- |
250
+ | DEX swap | Selected input/output token equality, wallet recipient, maximum input amount |
251
+ | Aave supply/withdraw/borrow/repay | Listed reserve token equality, wallet beneficiary, amount maximum |
252
+ | Moonwell/Venus mint/redeemUnderlying/borrow/repayBorrow | Maximum in the market's underlying-token units |
253
+ | EigenLayer deposit | Selected token equality and deposit amount maximum |
254
+ | Lido wrap/unwrap | stETH/wstETH input limits respectively; their units are not interchangeable |
255
+ | Lido submit | Native-value cap from the selected native asset's maxPerCall |
256
+
257
+ Aave reserve choices come from the reviewed official address book; fixed-token markets only enable for their actual underlying. Unknown assets do not receive an Aave approval or a positive Aave operation cap. A reserve listing is not a guarantee that its current supply cap, pause state or liquidity allows a transaction.
258
+
259
+ Market `redeem(uint256)` takes shares: it is excluded and `redeemUnderlying(uint256)` is provided instead. Lido's dynamic withdrawal arrays and position-based claims are also excluded because an underlying amount cap cannot safely be converted into those arguments by this pure helper. Custom rules remain possible through the normal rule API.
260
+
261
+ **A per-call limit applies to each allowed contract call, not the sum of several calls in one transaction. `maxTotal` is the cumulative Push-outbound amount, not lifetime turnover on the destination.** These statements also hold when a call's tokens are already in the CEA. Destination lifetime or batch-total accounting requires contract support. Bounded approvals do not supply such accounting.
262
+
263
+ The contract allows at most 32 pins across a universal rule. Expansion fails explicitly if the selected assets/apps exceed that ceiling; no restrictions are silently dropped. Two Aave reserves fit its four-operation template; three do not. Blank/incomplete inputs return zero-cap review calls, and regeneration replaces them with the selected token-specific calls.
191
264
 
192
265
  ## Validation
193
266
 
194
267
  Run `node packages/core/scripts/check-agw-docs.js` to typecheck these examples. Unit tests use the normal core Jest configuration. `jest.agw-local.config.ts` uses pinned real AGW contracts and a stub gateway. Live E2Es are opt-in under `__e2e__/agw`; preflight verifies the deployment and funding limits. Local tests do not prove destination delivery, and historical live results do not count as validation of a changed public API.
268
+
269
+
270
+ ### Live preset acceptance
271
+
272
+ The opt-in `agw-presets` E2E group exercises real Donut-to-Sepolia protocol calls. From `packages/core`, run `npm run e2e:preflight -- --group agw-presets --dry-run`, then `npm run e2e:ci -- --group agw-presets`. It uses the existing E2E credentials in memory. Each scenario funds a fresh wallet with at most 65 PC plus a fresh agent's configured gas allocation; the Uniswap case also uses 0.000002 pETH. No mainnet transaction is part of this group.
273
+
274
+ Uniswap uses destination WETH/Circle USDC; Aave uses its faucet LINK. Their generated preset calls and pins are retained, but bridge `assets` are set to `[]` because these destination tokens are not a supported SDK PRC20 pair. The owner funds the CEA separately. These tests establish swaps and lending against actual protocols, not the ability to bridge arbitrary assets. Missing liquidity, exhausted reserve caps or an unavailable faucet fail as prerequisites rather than silently skipping. Results are specific to Sepolia and do not certify the other catalog chains.
275
+
276
+
277
+ The additional opt-in group `agw-presets-expanded` covers EigenLayer deposits on Sepolia; Uniswap swaps on Base/Arbitrum Sepolia; PancakeSwap plus Venus on BNB testnet; and Aave plus Moonwell on Base Sepolia. Use the same preflight/run commands with `--group agw-presets-expanded`. Each scenario funds a fresh wallet with at most 100 PC and checks any required destination-native PRC20 before transfer. Native-wrap cases use 10^12 raw native-token units. These are deposit/swap/redemption checks, not borrow/repay or every-market coverage.
278
+
279
+ AGW token resolution uses the destination chain for ordinary token objects: an explicit Base or Arbitrum ETH token must not select Sepolia's PRC20 merely because its symbol/address is identical. An explicit Push PRC20 reference must name the same source chain as the destination; a mismatch fails before signing.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ @pushchain/core@6.0.27-alpha.2 (2026-10-16)
2
+
3
+ - feat: add bounded preset operations and configuration readiness
4
+
5
+ ---
6
+
7
+ @pushchain/core@6.0.27-alpha.1 (2026-10-15)
8
+
9
+ - fix: resolve AGW tokens by destination and expand live coverage
10
+ - feat: add mainnet AGW presets and live protocol coverage
11
+ - fix: return safe AGW preset review templates
12
+ - feat: add verified testnet AGW preset templates
13
+ - feat: migrate AGW SDK to deployed v6 contracts
14
+
15
+ ---
16
+
1
17
  @pushchain/core@6.0.27-alpha.0 (2026-10-12)
2
18
 
3
19
  - feat: align AGW rules and presets with October SDK feedback
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushchain/core",
3
- "version": "6.0.27-alpha.0",
3
+ "version": "6.0.27-alpha.2",
4
4
  "homepage": "https://push.org",
5
5
  "keywords": [
6
6
  "pushchain",
@@ -1,4 +1,5 @@
1
- /** Public section-6 rules and internal adapters for the deployed v5 wire format.
1
+ import type { ArgPinWire } from './codec/pins';
2
+ /** Public section-6 rules and internal adapters for the deployed v6 wire format.
2
3
  * Source snapshot: October 12, 2026. Internal normalized types are not package exports.
3
4
  */
4
5
  import type { Idl } from '@coral-xyz/anchor';
@@ -14,6 +15,7 @@ export type AgenticProgressHook = (event: ProgressEvent) => void;
14
15
  export type Selector = AgenticHex | `${string}(${string})`;
15
16
  /** One Push function a native rule allows, with its own limits and counters. */
16
17
  export interface NativeAction {
18
+ wirePins?: ArgPinWire[];
17
19
  target: AgenticAddress;
18
20
  selector: Selector | 'value-only';
19
21
  /** Default 0: no native PC value allowance. */
@@ -94,6 +96,7 @@ export interface AssetCap {
94
96
  maxTotal?: bigint;
95
97
  }
96
98
  export interface AllowedCall {
99
+ pins?: ArgPinWire[];
97
100
  target: AgenticAddress;
98
101
  selector: Selector;
99
102
  /** Argument index whose address must be the wallet's destination account. */
@@ -192,13 +195,15 @@ export interface InternalRulesRecord {
192
195
  }
193
196
  /** Current SDK section 6 public rule shape; contract wire types above are internal. */
194
197
  export type WalletMarker = 'agentic:wallet';
198
+ /** Top-level ABI argument, or a path through static tuple/fixed-array fields. */
199
+ export type ArgumentPath = number | readonly number[];
195
200
  export type Pin = {
196
- arg: number;
201
+ arg: ArgumentPath;
197
202
  expected: AgenticHex | AgenticAddress | bigint | WalletMarker;
198
203
  max?: never;
199
204
  account?: never;
200
205
  } | {
201
- arg: number;
206
+ arg: ArgumentPath;
202
207
  max: bigint;
203
208
  expected?: never;
204
209
  account?: never;
@@ -19,7 +19,7 @@ export declare enum AgenticCapability {
19
19
  ASSERT_SPENT_NATIVE = "assertSpentNative",
20
20
  /** checkpointCount + Checkpointed events. */
21
21
  CHECKPOINTS = "checkpoints",
22
- /** Agent-door EVM outbound composition against v5 per-token caps. */
22
+ /** Agent-door EVM outbound composition against v6 per-token caps. */
23
23
  UNIVERSAL_EVM_OUTBOUND = "universalEvmOutbound",
24
24
  /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */
25
25
  UNIVERSAL_EVM_RULES = "universalEvmRules",
@@ -26,7 +26,7 @@ var AgenticCapability;
26
26
  AgenticCapability["ASSERT_SPENT_NATIVE"] = "assertSpentNative";
27
27
  /** checkpointCount + Checkpointed events. */
28
28
  AgenticCapability["CHECKPOINTS"] = "checkpoints";
29
- /** Agent-door EVM outbound composition against v5 per-token caps. */
29
+ /** Agent-door EVM outbound composition against v6 per-token caps. */
30
30
  AgenticCapability["UNIVERSAL_EVM_OUTBOUND"] = "universalEvmOutbound";
31
31
  /** Target UniversalRule (assets[] / maxGasPerCall) encode/decode. A05/A07. */
32
32
  AgenticCapability["UNIVERSAL_EVM_RULES"] = "universalEvmRules";
@@ -13,3 +13,8 @@ export declare function argumentOffset(inputs: readonly AbiParameter[] | undefin
13
13
  export declare function encodeArgWord(param: AbiParameter, expected: AgenticHex | bigint | string | boolean, what: string): AgenticHex;
14
14
  /** Validate a raw calldata offset given directly (offset form). */
15
15
  export declare function rawOffset(offset: number, what: string): number;
16
+ /** Absolute location of a scalar reached through static tuple/fixed-array indexes. */
17
+ export declare function argumentLocation(inputs: readonly AbiParameter[] | undefined, arg: number | readonly number[], what: string): {
18
+ offset: number;
19
+ param: AbiParameter;
20
+ };
@@ -6,6 +6,7 @@ exports.isSingleWordStatic = isSingleWordStatic;
6
6
  exports.argumentOffset = argumentOffset;
7
7
  exports.encodeArgWord = encodeArgWord;
8
8
  exports.rawOffset = rawOffset;
9
+ exports.argumentLocation = argumentLocation;
9
10
  const viem_1 = require("viem");
10
11
  const errors_1 = require("../errors");
11
12
  /**
@@ -85,7 +86,8 @@ function encodeArgWord(param, expected, what) {
85
86
  try {
86
87
  const isWord = typeof expected === 'string' && (0, viem_1.isHex)(expected) && expected.length === 66;
87
88
  if (param.type === 'address' && !isWord) {
88
- if (typeof expected !== 'string' || !(0, viem_1.isAddress)(expected, { strict: false })) {
89
+ if (typeof expected !== 'string' ||
90
+ !(0, viem_1.isAddress)(expected, { strict: false })) {
89
91
  throw new Error('expected an address');
90
92
  }
91
93
  }
@@ -95,9 +97,13 @@ function encodeArgWord(param, expected, what) {
95
97
  }
96
98
  // An already-encoded 32-byte word (as decoded rules return) is accepted
97
99
  // when it is a canonical encoding of this argument type.
98
- if (typeof expected === 'string' && (0, viem_1.isHex)(expected) && expected.length === 66 && param.type !== 'bytes32') {
100
+ if (typeof expected === 'string' &&
101
+ (0, viem_1.isHex)(expected) &&
102
+ expected.length === 66 &&
103
+ param.type !== 'bytes32') {
99
104
  const [value] = (0, viem_1.decodeAbiParameters)([param], expected);
100
- if ((0, viem_1.encodeAbiParameters)([param], [value]).toLowerCase() !== expected.toLowerCase()) {
105
+ if ((0, viem_1.encodeAbiParameters)([param], [value]).toLowerCase() !==
106
+ expected.toLowerCase()) {
101
107
  throw new Error('word is not a canonical encoding');
102
108
  }
103
109
  return expected.toLowerCase();
@@ -118,4 +124,45 @@ function rawOffset(offset, what) {
118
124
  function invalid(message, cause) {
119
125
  return new errors_1.AgenticError(errors_1.AGENTIC_ERROR_CODE.INVALID_RULE, message, { cause });
120
126
  }
127
+ /** Absolute location of a scalar reached through static tuple/fixed-array indexes. */
128
+ function argumentLocation(inputs, arg, what) {
129
+ if (!inputs)
130
+ throw invalid(`${what} paths require a full function signature`);
131
+ const path = typeof arg === 'number' ? [arg] : arg;
132
+ if (!Array.isArray(path) ||
133
+ path.length === 0 ||
134
+ path.length > 16 ||
135
+ path.some((i) => !Number.isSafeInteger(i) || i < 0))
136
+ throw invalid(`${what} has an invalid argument path`);
137
+ if (path[0] >= inputs.length)
138
+ throw invalid(`${what} argument path is out of range`);
139
+ let offset = 4 + inputs.slice(0, path[0]).reduce((n, p) => n + headSize(p), 0);
140
+ let param = inputs[path[0]];
141
+ for (const index of path.slice(1)) {
142
+ if (isDynamic(param))
143
+ throw invalid(`${what} cannot descend into a dynamic argument`);
144
+ const arr = arraySuffix(param.type);
145
+ if (arr && arr.length !== null) {
146
+ if (!Number.isSafeInteger(arr.length) || index >= arr.length)
147
+ throw invalid(`${what} fixed-array index is out of range`);
148
+ const child = { ...param, type: arr.base };
149
+ offset += index * headSize(child);
150
+ param = child;
151
+ }
152
+ else if (param.type === 'tuple') {
153
+ const fields = components(param);
154
+ if (index >= fields.length)
155
+ throw invalid(`${what} tuple index is out of range`);
156
+ offset += fields.slice(0, index).reduce((n, p) => n + headSize(p), 0);
157
+ param = fields[index];
158
+ }
159
+ else
160
+ throw invalid(`${what} path descends into a scalar`);
161
+ }
162
+ if (!isSingleWordStatic(param) ||
163
+ !Number.isSafeInteger(offset) ||
164
+ offset + 32 > UINT16_MAX)
165
+ throw invalid(`${what} must identify one static ABI word within the uint16 offset range`);
166
+ return { offset, param };
167
+ }
121
168
  //# sourceMappingURL=abi-layout.js.map
@@ -4,13 +4,13 @@
4
4
  * a fallback for these fields; update this table for future changes.
5
5
  *
6
6
  * Explicit zero always stays zero. In the native policy a zero value/amount
7
- * cap forbids positive value/amount, while maxCalls = 0 means unlimited.
7
+ * cap forbids positive value/amount, while maxCalls = uint32 maximum means unlimited.
8
8
  */
9
9
  export declare const UINT256_MAX: bigint;
10
10
  export interface DefaultRow {
11
11
  value: bigint;
12
12
  meaning: string;
13
- source: 'product' | 'v5';
13
+ source: 'product' | 'v6';
14
14
  }
15
15
  export declare const AGENTIC_DEFAULTS: {
16
16
  readonly native: {
@@ -8,7 +8,7 @@ exports.withDefault = withDefault;
8
8
  * a fallback for these fields; update this table for future changes.
9
9
  *
10
10
  * Explicit zero always stays zero. In the native policy a zero value/amount
11
- * cap forbids positive value/amount, while maxCalls = 0 means unlimited.
11
+ * cap forbids positive value/amount, while maxCalls = uint32 maximum means unlimited.
12
12
  */
13
13
  exports.UINT256_MAX = BigInt(2) ** BigInt(256) - BigInt(1);
14
14
  exports.AGENTIC_DEFAULTS = {
@@ -29,7 +29,7 @@ exports.AGENTIC_DEFAULTS = {
29
29
  source: 'product',
30
30
  },
31
31
  maxCalls: {
32
- value: BigInt(0),
32
+ value: BigInt(0xffffffff),
33
33
  meaning: 'unlimited calls until expiry',
34
34
  source: 'product',
35
35
  },
@@ -1,6 +1,6 @@
1
1
  import { type Address, type Hex } from 'viem';
2
2
  /**
3
- * Pure identity helpers mirroring the pinned AGW generation (v5):
3
+ * Pure identity helpers mirroring the pinned AGW generation (v6):
4
4
  * smartsessions IdLib.toActionId / toConfigId / toPermissionId and
5
5
  * AGWFactory._predict (OZ Clones immutable-args CREATE2).
6
6
  * Every input that changes the result is explicit — validator, factory and
@@ -8,7 +8,7 @@ exports.deriveWallet = deriveWallet;
8
8
  const viem_1 = require("viem");
9
9
  const errors_1 = require("../errors");
10
10
  /**
11
- * Pure identity helpers mirroring the pinned AGW generation (v5):
11
+ * Pure identity helpers mirroring the pinned AGW generation (v6):
12
12
  * smartsessions IdLib.toActionId / toConfigId / toPermissionId and
13
13
  * AGWFactory._predict (OZ Clones immutable-args CREATE2).
14
14
  * Every input that changes the result is explicit — validator, factory and
@@ -1,10 +1,11 @@
1
+ import { type ArgPinWire } from './pins';
1
2
  import { type AbiParameter, type Address, type Hex } from 'viem';
2
3
  import type { NativeAction, NativeRule, NativeSingleRule } from '../agentic.types';
3
4
  import { type ParsedSelector } from './selectors';
4
- /** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */
5
+ /** URP native limits at v6 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */
5
6
  export declare const MAX_PINS = 8;
6
7
  export declare const MAX_NATIVE_ACTIONS = 8;
7
- /** NativeTerms (Types.sol:354-363 at v5). */
8
+ /** NativeTerms in the pinned v6 Types.sol. */
8
9
  export interface NativeTermsWire {
9
10
  validUntil: number;
10
11
  target: Address;
@@ -18,10 +19,7 @@ export interface NativeTermsWire {
18
19
  maxTotal: bigint;
19
20
  };
20
21
  maxCalls: number;
21
- pins: readonly {
22
- offset: number;
23
- expected: Hex;
24
- }[];
22
+ pins: readonly ArgPinWire[];
25
23
  }
26
24
  export declare const NATIVE_TERMS_PARAM: AbiParameter;
27
25
  export interface NativeEncodeContext {
@@ -10,12 +10,13 @@ exports.decodeNativeTerms = decodeNativeTerms;
10
10
  exports.nativeTermsToRule = nativeTermsToRule;
11
11
  exports.nativeActionTermsToRule = nativeActionTermsToRule;
12
12
  exports.isUnlimited = isUnlimited;
13
+ const pins_1 = require("./pins");
13
14
  const viem_1 = require("viem");
14
15
  const errors_1 = require("../errors");
15
16
  const abi_layout_1 = require("./abi-layout");
16
17
  const defaults_1 = require("./defaults");
17
18
  const selectors_1 = require("./selectors");
18
- /** URP native limits at v5 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */
19
+ /** URP native limits at v6 (Types.sol MAX_PINS, AGW MAX_NATIVE_ACTIONS). */
19
20
  exports.MAX_PINS = 8;
20
21
  exports.MAX_NATIVE_ACTIONS = 8;
21
22
  const UINT32_MAX = 2 ** 32 - 1;
@@ -42,10 +43,7 @@ exports.NATIVE_TERMS_PARAM = {
42
43
  {
43
44
  name: 'pins',
44
45
  type: 'tuple[]',
45
- components: [
46
- { name: 'offset', type: 'uint16' },
47
- { name: 'expected', type: 'bytes32' },
48
- ],
46
+ components: pins_1.ARG_PIN_COMPONENTS,
49
47
  },
50
48
  ],
51
49
  };
@@ -68,6 +66,7 @@ const SINGLE_ACTION_FIELDS = [
68
66
  'maxValueTotal',
69
67
  'maxCalls',
70
68
  'pins',
69
+ 'wirePins',
71
70
  'amount',
72
71
  ];
73
72
  /**
@@ -106,6 +105,7 @@ function nativeActionsOf(rule) {
106
105
  maxValueTotal: single.maxValueTotal,
107
106
  maxCalls: single.maxCalls,
108
107
  pins: single.pins,
108
+ wirePins: single.wirePins,
109
109
  amount: single.amount,
110
110
  validUntil: single.validUntil,
111
111
  },
@@ -171,7 +171,8 @@ function nativeActionToTerms(rule, ctx) {
171
171
  }
172
172
  const parsed = (0, selectors_1.parseSelector)(rule.selector);
173
173
  const pinsIn = rule.pins ?? [];
174
- if (parsed.valueOnly && (pinsIn.length > 0 || rule.amount)) {
174
+ if (parsed.valueOnly &&
175
+ (pinsIn.length > 0 || rule.wirePins?.length || rule.amount)) {
175
176
  throw invalid('a value-only rule cannot carry pins or an amount rule');
176
177
  }
177
178
  if (pinsIn.length > exports.MAX_PINS) {
@@ -243,9 +244,20 @@ function nativeActionToTerms(rule, ctx) {
243
244
  const maxCalls = rule.maxCalls === undefined
244
245
  ? Number(defaults_1.AGENTIC_DEFAULTS.native.maxCalls.value)
245
246
  : rule.maxCalls;
246
- if (!Number.isInteger(maxCalls) || maxCalls < 0 || maxCalls > UINT32_MAX) {
247
+ if (!Number.isInteger(maxCalls) || maxCalls <= 0 || maxCalls > UINT32_MAX) {
247
248
  throw invalid('maxCalls must be a uint32 integer');
248
249
  }
250
+ try {
251
+ (0, pins_1.validatePins)(rule.wirePins ??
252
+ pins.map((p) => ({
253
+ offset: p.offset,
254
+ op: 0,
255
+ value: p.expected,
256
+ })));
257
+ }
258
+ catch (error) {
259
+ throw invalid(error.message);
260
+ }
249
261
  return {
250
262
  parsed,
251
263
  terms: {
@@ -256,7 +268,12 @@ function nativeActionToTerms(rule, ctx) {
256
268
  maxValueTotal,
257
269
  amount,
258
270
  maxCalls,
259
- pins,
271
+ pins: rule.wirePins ??
272
+ pins.map((p) => ({
273
+ offset: p.offset,
274
+ op: 0,
275
+ value: p.expected,
276
+ })),
260
277
  },
261
278
  };
262
279
  }
@@ -285,12 +302,8 @@ function nativeTermsToRule(terms, agent) {
285
302
  maxValueTotal: terms.maxValueTotal,
286
303
  maxCalls: Number(terms.maxCalls),
287
304
  };
288
- if (terms.pins.length > 0) {
289
- rule.pins = terms.pins.map((p) => ({
290
- offset: Number(p.offset),
291
- expected: p.expected.toLowerCase(),
292
- }));
293
- }
305
+ if (terms.pins.length > 0)
306
+ rule.wirePins = terms.pins.map((p) => ({ ...p }));
294
307
  if (terms.amount.enabled) {
295
308
  rule.amount = {
296
309
  offset: Number(terms.amount.offset),
@@ -0,0 +1,20 @@
1
+ import type { Hex } from 'viem';
2
+ export interface ArgPinWire {
3
+ offset: number;
4
+ op: 0 | 1;
5
+ value: Hex;
6
+ }
7
+ export declare const ARG_PIN_COMPONENTS: readonly [{
8
+ readonly name: "offset";
9
+ readonly type: "uint16";
10
+ }, {
11
+ readonly name: "op";
12
+ readonly type: "uint8";
13
+ }, {
14
+ readonly name: "value";
15
+ readonly type: "bytes32";
16
+ }];
17
+ export declare const UNLIMITED_CALLS = 4294967295;
18
+ export declare const ANY_ACCOUNT_COUNT = 255;
19
+ /** Validate every encoded constraint before signing. */
20
+ export declare function validatePins(pins: readonly ArgPinWire[]): void;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ANY_ACCOUNT_COUNT = exports.UNLIMITED_CALLS = exports.ARG_PIN_COMPONENTS = void 0;
4
+ exports.validatePins = validatePins;
5
+ exports.ARG_PIN_COMPONENTS = [
6
+ { name: 'offset', type: 'uint16' },
7
+ { name: 'op', type: 'uint8' },
8
+ { name: 'value', type: 'bytes32' },
9
+ ];
10
+ exports.UNLIMITED_CALLS = 0xffffffff;
11
+ exports.ANY_ACCOUNT_COUNT = 255;
12
+ /** Validate every encoded constraint before signing. */
13
+ function validatePins(pins) {
14
+ if (!Array.isArray(pins) || pins.length > 8)
15
+ throw new Error('pins must contain at most eight constraints');
16
+ const seen = new Set();
17
+ for (const p of pins) {
18
+ if (!Number.isInteger(p.offset) ||
19
+ p.offset < 4 ||
20
+ p.offset + 32 > 65535 ||
21
+ ![0, 1].includes(p.op) ||
22
+ !/^0x[0-9a-fA-F]{64}$/.test(p.value))
23
+ throw new Error('invalid argument pin');
24
+ if (seen.has(p.offset))
25
+ throw new Error('duplicate pin offset');
26
+ seen.add(p.offset);
27
+ }
28
+ }
29
+ //# sourceMappingURL=pins.js.map
@@ -38,7 +38,7 @@ export interface PreparedRule {
38
38
  universalTerms?: UniversalTermsWire;
39
39
  svmTerms?: SvmTermsWire;
40
40
  }
41
- /** Validate before signing. V5 permits several grants for the same agent/chain. */
41
+ /** Validate before signing. V6 permits several grants for the same agent/chain. */
42
42
  export declare function prepareRules(rules: readonly InternalRule[], ctx: RuleEncodeContext & {
43
43
  /** Wallet owner; when given, an agent equal to it is AGENT_IS_OWNER. */
44
44
  owner?: Address;